← Back to DevBytes

VS Code Remote Development: Complete Guide

VS Code Remote Development: Complete Guide

Visual Studio Code's Remote Development extension pack is one of the most transformative features Microsoft has shipped for the editor. It allows you to open any folder, container, or remote machine as if it were a local project, running the full VS Code experience — IntelliSense, debugging, terminals, extensions — wherever your code actually lives. This guide walks through everything you need to know to use it effectively.

What Is Remote Development?

Remote Development is a collection of VS Code extensions that let the editor's UI run on your local machine while the actual workspace — file system, language servers, terminals, and extensions — runs somewhere else. VS Code splits itself into a UI client and a server component. The server is a small Node process that VS Code installs automatically on the remote target.

The extension pack includes three core extensions:

Why It Matters

Developers rarely work in a single, clean environment anymore. You might have a Node service on a cloud VM, a Python pipeline in a Docker container, and a Rust binary on a Raspberry Pi. Without Remote Development, you'd juggle SSH terminals, manual file syncs, and inconsistent tooling. With it, you get a single, consistent editing experience regardless of where the code runs.

Key benefits include:

Prerequisites and Installation

Before you start, install the prerequisites for your chosen workflow. All workflows require VS Code itself.

For SSH, you need an OpenSSH-compatible client on your local machine and an SSH server on the remote host. For Dev Containers, you need Docker Desktop or a compatible Docker engine. For WSL, you need WSL 2 installed on Windows.

Install the extension pack from the marketplace:

# From the command palette (Ctrl/Cmd+Shift+P), run:
# "Extensions: Install Extensions" and search for "Remote Development"

# Or via CLI:
code --install-extension ms-vscode-remote.vscode-remote-extension-pack

Connecting Over SSH

Remote - SSH is the most flexible option. It works with any host you can SSH into: a cloud VM, a bare-metal server, or even a Raspberry Pi on your local network.

Start by defining your SSH host in your local SSH config file, typically at ~/.ssh/config:

# ~/.ssh/config
Host dev-server
    HostName 203.0.113.42
    User ubuntu
    IdentityFile ~/.ssh/id_ed25519
    ForwardAgent yes

Then connect from VS Code:

# Command Palette > "Remote-SSH: Connect to Host..."
# Select "dev-server" from the list

# Or from the terminal:
code --remote ssh-remote+dev-server /home/ubuntu/projects/myapp

The first connection takes a moment because VS Code downloads and installs its server component to ~/.vscode-server on the remote host. Subsequent connections are much faster. Once connected, the window title bar shows the host name, and every terminal, task, and extension runs remotely.

Working With Dev Containers

Dev Containers let you define your development environment as code. The definition lives in a .devcontainer/devcontainer.json file (optionally with a Dockerfile or docker-compose.yml) at the root of your repository.

Here is a complete example for a Node.js + PostgreSQL project:

// .devcontainer/devcontainer.json
{
  "name": "Node + Postgres Dev",
  "dockerComposeFile": "docker-compose.yml",
  "service": "app",
  "workspaceFolder": "/workspace",
  "forwardPorts": [5432, 3000],
  "postCreateCommand": "npm install",
  "customizations": {
    "vscode": {
      "extensions": [
        "dbaeumer.vscode-eslint",
        "esbenp.prettier-vscode",
        "ms-ossdata.vscode-postgresql"
      ],
      "settings": {
        "editor.formatOnSave": true,
        "editor.defaultFormatter": "esbenp.prettier-vscode"
      }
    }
  },
  "remoteUser": "node"
}
# .devcontainer/docker-compose.yml
version: "3.8"
services:
  app:
    build:
      context: ..
      dockerfile: .devcontainer/Dockerfile
    volumes:
      - ..:/workspace:cached
    command: sleep infinity
    depends_on:
      - db
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: dev
      POSTGRES_PASSWORD: dev
      POSTGRES_DB: appdb
    ports:
      - "5432:5432"
# .devcontainer/Dockerfile
FROM mcr.microsoft.com/devcontainers/javascript-node:20

RUN apt-get update && apt-get install -y \
    postgresql-client \
    && rm -rf /var/lib/apt/lists/*

Open the project folder in VS Code, then run Dev Containers: Reopen in Container from the command palette. VS Code builds the image, starts the compose stack, and reconnects inside the container. The Postgres database is reachable at localhost:5432 from your host machine because of forwardPorts.

Using WSL on Windows

If you develop on Windows but target Linux, WSL integration is essential. Install a Linux distribution via wsl --install -d Ubuntu, then install the WSL extension in VS Code. Open a WSL terminal, navigate to your project, and run:

# Inside WSL
cd /home/$USER/projects/myapp
code .

VS Code launches and connects to WSL automatically. File operations, the integrated terminal, and language servers all run inside Linux, giving you native performance for Linux-targeted toolchains like Docker, Node, Python, and Go.

Managing Extensions Remotely

Extensions are installed per-environment. An extension installed locally does not automatically run remotely, and vice versa. This separation keeps each environment clean but requires deliberate management.

You can force certain extensions to install everywhere by adding them to your user settings:

// settings.json
{
  "remote.SSH.defaultExtensions": [
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode"
  ]
}

For dev containers, prefer declaring extensions in devcontainer.json so every contributor gets the same set automatically.

Debugging Remotely

Debugging works identically to local development. Launch configurations run on the remote host, and VS Code's debugger attaches over the same channel it uses for everything else. Here is a Node.js launch config that works inside a dev container:

// .vscode/launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Debug API",
      "skipFiles": ["<node_internals>/**"],
      "program": "${workspaceFolder}/src/index.js",
      "env": {
        "NODE_ENV": "development",
        "DATABASE_URL": "postgres://dev:dev@db:5432/appdb"
      }
    }
  ]
}

Press F5 and breakpoints hit just as they would locally. The same pattern applies to Python (debugpy), Go (dlv), and Java.

Port Forwarding

When a process inside the remote environment listens on a port, VS Code can automatically forward it to your local machine so you can open it in a browser. You can also forward ports manually:

# Command Palette > "Forward a Port"
# Enter 8080

# Or in the integrated terminal, VS Code detects the port
# and prompts to forward automatically

For persistent forwards in dev containers, list them in forwardPorts in your devcontainer.json. For SSH, add them to your SSH config with LocalForward directives.

Best Practices

Troubleshooting Common Issues

If the SSH connection hangs during server installation, check that the remote host has enough disk space in the home directory and that wget or curl is available. You can manually clean a broken install:

# On the remote host
rm -rf ~/.vscode-server

If a dev container fails to build, open the command palette and run Dev Containers: Rebuild Without Cache to rule out stale Docker layers. For compose-based setups, run docker compose -f .devcontainer/docker-compose.yml logs to inspect service output.

If WSL feels slow, make sure your project files live inside the WSL filesystem (for example /home/user/) rather than on the Windows mount (/mnt/c/). Cross-filesystem access incurs significant overhead.

Conclusion

VS Code Remote Development collapses the distance between your editor and your runtime environment. Whether you are SSHing into a production-like VM, spinning up a reproducible dev container, or bridging Windows and Linux through WSL, the same editor, the same keybindings, and the same debugging workflow follow you everywhere. By treating your development environment as versioned infrastructure — defined in devcontainer.json, secured over SSH, and tuned with the best practices above — you eliminate an entire class of setup friction and let your team focus on shipping code instead of fighting their machines.

— Ad —

Google AdSense will appear here after approval

← Back to all articles