Setting up Zed with Ruby LSP
(Last updated: 2025-04-18)
Zed is a modern, high-performance code editor that’s gaining popularity. After several years of using VS Code, I’ve been trying it out for writing Ruby and I’ve been impressed. With recent rapid development in AI, Zed’s close collaboration with Anthropic makes it a strong contender to VS Code derived editors such as Cursor.
In this post you’ll learn how to set up Ruby LSP with Zed, and how to troubleshoot if things aren’t working. I’ll also share some alternatives for features that aren’t currently available in Zed.
Setting up Ruby Support
Zed’s Ruby support comes from the official Ruby extension, created by Vitaly Slobodin. You can enable it through zed: extensions
.
As with all Zed extensions, it is written in Rust. Its documentation can be found here, as part of the official docs.
Configuring Ruby LSP
Zed has good built-in support for the Language Server Protocol, meaning there’s a lot of tooling already available that can be used.
Zed defaults to using Solargraph as its language server for Ruby, but my preference is to use Ruby LSP, since I’m a contributor.
You’ll also be able to take advantage of Ruby LSP add-ons such as ruby-lsp-rails and ruby-lsp-rspec.
It can configured in Zed’s settings as follows:
{
"languages": {
"Ruby": {
"language_servers": ["ruby-lsp"]
}
}
}
(The docs suggest disabling each language server that you don’t want with !
, and using "..."
to enable the rest, but I find it simpler to just list the ones you do want).
Note: I’ve noticed that some configuration changes don’t seem to apply until you fully quit and reload the editor (workspace: reload
isn’t enough), so you may need to do that in some situations.
To verify things are working, open a Ruby file, then choose debug: open language server logs
from the command menu. The output should look something like this:
If there are multiple language servers running, then you’ll need to first select the ruby-lsp
log from the menu at the top left.
If ever it seems that Ruby LSP is not running, this is the first place to check for errors.
Enabling Diagnostics
The Diagnostics feature is used by Ruby LSP to show possible errors as you type, as illustrated here.
The implementation uses pull diagnostics, a newer aspect of the LSP specification where the client requests diagnostics from the server, instead of the server notifying the client.
There is some work in progress for supporting this in Zed, but until then there is a workaround as long as your project uses RuboCop.
First, a little background: RuboCop introduced a language server in v1.53, and the Zed extension already has built-in support for it. This language server does not use pull diagnostics, so its diagnostics are compatible with Zed.
Normally when using Ruby LSP we don’t need RuboCop’s own language server since its built-in, but here it becomes a useful fallback. We can configure Zed such that we use RuboCop’s LSP only for diagnostics, and Ruby LSP for everything else. First, we’ll disable diagnostics
for Ruby LSP to avoid sending unnecessary requests:
{
"lsp": {
"ruby-lsp": {
"initialization_options": {
"enabledFeatures": {
"diagnostics": false
}
}
}
}
}
Note: The values for initialization_options
are passed directly to Ruby LSP. You can see the full list here.
Then we’ll add rubocop
as a secondary language server for Ruby:
{
"languages": {
"Ruby": {
"language_servers": ["ruby-lsp", "rubocop"],
}
}
}
Note: Although apparently not documented, it seems that the order is important as only the first language server entry is use for formatting.
If your project uses Standard rather than RuboCop then you can try this branch.
Disable onTypeFormatting
There is known issue in Ruby LSP with cursor placement when trying to type a |
for block arguments, so you may want to disable onTypeFormatting
for now:
{
"lsp": {
"ruby-lsp": {
"initialization_options": {
"enabledFeatures": {
"onTypeFormatting": false,
}
}
}
}
}
Global vs Local Settings
So far I’ve shown settings as being added to the Zed’s global configuration.
If you only ever work on a single Ruby project, then it doesn’t really matter if you all your settings are global. But many of us work on codebases with different configurations, such as for linting and formatting, so having more granular control is often necessary.
You can add project-specific settings to .zed/settings.json
in your project directory. These settings will be merged with the global settings, so normally you’ll only need a few lines of configuration.
For example, you might have some projects that use RuboCop but others that use Standard.
Running tests
One very useful feature when using Ruby LSP in VS Code is Code Lens, which adds a Run in Terminal
link to each test, and shows the result in the integrated terminal.
This LSP feature is not supported by Zed, but we can use the powerful Tasks feature to do something similar.
For example, to add a task for running Rails tests, we can create a .zed/tasks.json
file:
[
{
"label": "test $ZED_RELATIVE_FILE:$ZED_ROW",
"command": "bundle exec rails",
"args": ["test", "\"$ZED_RELATIVE_FILE:$ZED_ROW\""],
"tags": ["ruby-test"]
}
]
The test can be run by clicking on the ▷
in the gutter, or with the Command-Shift-R keybinding.
Advanced LSP Troubleshooting
It can sometimes be useful see the underlying requests and responses for the language server. In the debug: language server logs
window, click the second menu, then enable RPC Messages
:
What’s Missing
-
If you’re coming from VS Code with Ruby LSP, you might notice some features are not available. There’s two main reasons behind this:
-
Some Ruby LSP features depends on custom behaviour in the VS Code extension. Those would need to be reimplemented for Zed within the Ruby extension.
-
Some parts of the LSP specification are not yet implemented in Zed. You can follow this Zed issue to learn more.
-
-
Changes aren’t indexed until Zed is restarted. See Shopify/ruby-lsp#3384.
-
Zed does not yet have a visual debugger, so if you’re used to that in VS Code then it might be a little awkward to use terminal-based debugging. A preview of a debugger was recently merged. I haven’t tried it yet but I expect that it eventually be usable for Ruby.
-
Zed supports Snippets but the Ruby extension doesn’t yet have any. I have a PR in progress to add them.
Other Useful Resources
For ERB, erb-formatter works well.
For working with Hotwire, there is the Zed Stimulus extension.
To toggle between a test and its implementation, try zed-test-toggle.