Skip to content
Mick Zijdel

Setting Up a Debugger and Intellisense for Ruby on Rails 8 in Visual Studio Code/Cursor/Windsurf/etc

May 19, 2025 9 min read

If you are confused by this guide or notice a mistake, please get in touch so I can fix it.

So, allegedly it’s very easy to set up a debugger for Ruby on Rails in Visual Studio Code. That was not my experience. Fortunately, after a few hours of messing around, I got it working pretty robustly with the following versions:

  • Ruby on Rails 8.0.2
  • Visual Studio Code 1.100.2
  • Debug 1.10.0
  • rdbg 0.1.0
  • foreman 0.88.1

Debugger

It works somewhat fine if I directly start rails server with rdbg, but it’s not robust and does not work with bin/dev so you can’t automatically run auxillary services, so, this setup launches bin/dev in the background and then attaches.

You can also find all the files here.

Packages

gem "rdbg" # Ruby debug integration
gem "foreman" # Necessary for the procfile to work

Visual Studio Code

Install the Visual Studio Code rdbg Ruby Debug extension by Koichi Sasada.

Configuration Files

Update or create the following files:

.vscode/launch.json

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "rdbg",
      "name": "Run bin/dev & Attach rdbg",
      "request": "attach",
      "preLaunchTask": "runBinDev",
      "localfs": true,
      "localfsMap": "${workspaceFolder}:${workspaceFolder}"
    },
    {
      "type": "rdbg",
      "name": "Attach with rdbg",
      "request": "attach",
      "localfs": true,
      "localfsMap": "${workspaceFolder}:${workspaceFolder}"
    },
  ]
}

.vscode/tasks.json

Define the pre-launch task to start up the server using bin/dev. Note that using this method, the server will keep running when you stop debugging, and you can re-attach by running the same debug configuration again.

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "runBinDev",
      "type": "shell",
      "command": "bin/dev",
      "isBackground": true,
      "problemMatcher": [
        {
          "owner": "custom-rdbg-task",
          "pattern": [
            {
              "regexp": "^.*DEBUGGER: Debugger can attach.*$",
              "kind": "info",
              "file": 1,
              "location": 1,
              "message": 0
            }
          ],
          "background": {
            "activeOnStart": true,
            "beginsPattern": "^.*DEBUGGER: Debugger can attach.*$",
            "endsPattern": "^.*DEBUGGER: Debugger can attach.*$"
          }
        }
      ],
      "presentation": {
        "reveal": "always",
        "panel": "dedicated",
        "clear": true
      },
      "group": {
        "kind": "build",
        "isDefault": false
      }
    }
  // If you have other tasks, they would be here
  ]
}

Procfile.dev

Make sure the web: line looks like this, with a call to rdbg, and leave the rest the same:

web: RUBY_DEBUG_OPEN=TRUE RUBY_DEBUG_NONSTOP=TRUE rdbg --command --open --stop-at-load -- bundle exec bin/rails server -p 3000

You can leave bin/dev intact.

I am not sure how it would work if you had multiple processes you want to debug. You might be able to open both of them with rdbg and see if they attach to both simultaneously.

Testing

When you now go to the ‘Run and Debug’ tab, you can now select the “Run bin/dev & Attach rdbg” and run it. After selecting it, you can also use the shortcut F5.

You can set breakpoints on the left side of the editor next to the line number, and enable automatically pausing on exceptions and errors in the bottom of the “Run and Debug” tab.

As I said before, using this method, the server will keep running when you stop debugging, and you can re-attach by running the same debug configuration again.

Troubleshooting

Error during server startup when “rescue any exception” or “rescue RuntimeError” is enabled

I am also not sure why this happens, but it is harmless. You can either press continue until you’ve skipped through all the errors, or untick those boxes for startup. If you know how to get around this, please let me know.

Cannot find the TCP port

You can try to explicitly define a port in the rdbg call in Procfile.dev and the attach call in launch.json

In Procfile.dev, add --port=12345 after the --command --open part of the rdbg command.

In launch.json, add the following line to both launch configurations:

"port": 12345

Making sure the debugger gem is working

You can temporarily add an initializer, like debug.rb, to the initializers folder:

if defined?(DEBUGGER__)
  puts "Debugger support loaded successfully"

  puts "Current directory: #{Dir.pwd}"
  puts "Rails root: #{Rails.root}" if defined?(Rails)

  # Force a breakpoint to check if debugging works at all
  binding.break
end

If you launch with rdbg and it stops at binding.break, you can be confident that the debug and rdbg gems are set up fine.

Intellisense

There are two ways to set up intellisense in Visual Studio Code: Solargraph and Ruby LSP. Solargraph is older and more robust, but Ruby LSP is newer, faster, has more features and better Rails integration.

Solargraph

install the VS Code Extension.

Update your Gemfile to include the Solargraph gem:

group :development, :test do
  gem "solargraph", require: false
end

Run this command to install the gem and generate the binstubs

bundle install
bundle binstubs solargraph

Create a .solargraph.yml file in the project root:

include:
- "**/*.rb"
exclude:
- spec/**/*
- test/**/*
- vendor/**/*
- ".bundle/**/*"
require: []
domains: []
reporters:
- rubocop
- require_not_found
formatter:
  rubocop:
    cops: safe
    except: []
    only: []
    extra_args: []
require_paths: []
plugins: []
max_files: 5000

Restarting should now start Solagraph. After restarting, check if you have any notifications in the bottom of your screen giving any solargraph issues. If it says the bin/solargraph folder is missing, make sure to generate binstubs as per above. Hover over a function definition in a Ruby file to see if anything pops up with context or start typing and see if it starts auto-completing (manually trigger with ctrl+space).

Ruby LSP

I can’t quite get this working in my setup, but it might help you on your way:

Install the VS Code add-on.

and add to your Gemfile:

gem "ruby-lsp-rails", require: false

Restart Visual Studio Code, and open a Ruby file. There should be a {} Ruby tab in the bottom right. Click this for the Ruby LSP status.

You might need to add the Ruby version manager manually to your .vscode/settings.json file. Find the options here:

{
  "rubyLsp.rubyVersionManager": {
    "identifier": "auto/none/custom/asdf/chruby/rbenv/rvm/shadowenv/mise",
  },
}

In my case, it could not find my mise install, so I had to set it manually (which I did globally):

{
  "rubyLsp.rubyExecutablePath": "<path-to-your-ruby-as-I-got-from-"mise bin-paths">"
}

Typechecking with Sorbet and Tapioca

You can also set up type-checking for Ruby with Sorbet and Tapioca. Tapioca is still in alpha and it’s not working for me, but it should go like this.

Install the VS Code extension.

Add the gems to your Gemfile:

gem "sorbet", group: :development
gem "sorbet-runtime"
gem "tapioca"

Then run the following commands:

bundle install

bundle exec tapioca init

bin/tapioca dsl
bin/tapioca gems

srb tc

If this doesn’t work, you can check the sorbet and tapioca docs.

Subscribe to the Newsletter

Enjoyed this article? Subscribe to get notified when I publish new content.

No spam. Unsubscribe at any time. Or let's RSS.