10 min read

From VS Code (and friends) to Zed

A practical migration guide. What to install, configure, and expect. Covers extensions, settings, git, AI agents, and keyboard shortcuts.
From VS Code (and friends) to Zed

But why?

Have you seen the news lately? VSCode is becoming a bit of a liability.

  1. GitHub breached via poisoned Nx Console extension (May 2026)
  2. MaliciousCorgi — fake AI assistants stealing source code (January 2026)
  3. Shai-Hulud 2.0 worm — AsyncAPI compromise (November 2025)
  4. Prettier impersonation → Anivia loader → OctoRAT (November 2025)
  5. GlassWorm self-propagating campaign (October 2025 – April 2026)
  6. 550+ secrets leaked across 500+ extensions (October 2025)

... and on and on.

One of the best things about VScode, the power, flexibility, breadth and depth of its plugins, is now one of its biggest weaknesses.

Similarly, the electron base that made it cross platform and easy to run, is kinda... big and slow.

Zed is the speed demon that makes VS Code and Antigravity feel sluggish
A new and faster code editor emerges

I've tried to move to Zed a few times, but the final nail was my VSCode flavor of choice (Windsurf) finally going "full AI", and becoming Devin Desktop.

Windsurf is now Devin Desktop
The next generation of Windsurf: a full IDE with the Agent Command Center built in for managing fleets of local and cloud agents from one surface.

That was the final push I needed.

Shut up and setup my Zed

Okay, okay. Fork this and run install.sh:

GitHub - a-c-m/my-zed-config: Like the title says, my Zed config.
Like the title says, my Zed config. Contribute to a-c-m/my-zed-config development by creating an account on GitHub.

It symlinks the config files into ~/.config/zed/ and installs Zed and JetBrains Mono Font via Homebrew.

Because it symlinks (not copies), any changes you make in Zed show up as git diffs in the repo for you to keep, discard the rest as needed. Your config is version-controlled as you go.

Otherwise, here it is in a bit more detail.


1. Install

Direct download (recommended) → zed.dev/download

Homebrew (Mac)

brew install --cask zed

CLI tool (optional, but recomended) open projects from terminal:

# Command Palette → "zed: install CLI"
zed .          # open current folder
zed file.ts    # open a file
Stable vs Preview: Stable is fine for daily use. Preview gets features ~1 week earlier but ships more bugs. You can install both and switch.

2. First-run: set your keymap

The single most important setting. Add to ~/.config/zed/settings.json:

{
  "base_keymap": "VSCode"
}

This gets you ~80% of muscle memory working immediately. E.g.
⌘P (file picker),
⌘⇧P (command palette),
⌘D (multi-select),
⌘` (terminal).
The remaining gaps are covered in the shortcuts section below.

Other options: "JetBrains", "Atom", "Emacs", "SublimeText", "TextMate".

3. Extensions. Install these first

Open extensions: ⌘⇧X or Command Palette → zed: extensions

Extension What it does Replaces
Codebook Spell checker that understands camelCase and code identifiers Code Spell Checker
Typos Low-noise typo detection in identifiers, very few false positives (no VS Code equivalent)
Colored Zed Icons Theme The default Zed file icons, but coloured, makes the file tree much easier to scan File icon themes in VS Code
Biome Fast linter + formatter for JS/TS/JSON (replaces ESLint + Prettier) ESLint, Prettier
Skip the manual step: If you fork my-zed-config, Codebook, Biome, and Colored Zed Icons Theme are listed under `auto_install_extensions`. Makes Zed install them automatically on first launch.
On extension security: Zed extensions are compiled to WebAssembly with a restricted API surface. They cannot run arbitrary host processes the way VS Code extensions can. A meaningful security improvement over the VS Code extension model, which has seen a wave of supply-chain attacks in 2025–2026.

4. Themes

Switch themes live with ⌘K ⌘T, arrow keys preview in real time, Enter saves.

Built-in themes are decent (no install needed):

  • One Dark / One Light are good defaults, most people stick with these
  • Gruvbox Dark / Gruvbox Light / Gruvbox Dark Hard
  • Ayu Dark / Ayu Light / Ayu Mirage

More themes available via ⌘⇧X and at zed-themes.com.

Icon themes: Zed supports icon themes separately from colour themes. Colored Zed Icons Theme is the most popular. File icons are nice, colours are better.
Install from ⌘⇧X and activate via Command Palette → theme selector: toggle icons.

Per-project theming: No Peacock (sadly). But you can set "theme" in .zed/settings.json at the repo root.

Markdown tip: theme choice significantly affects Markdown legibility. `Gruvbox Dark Hard` and `Ayu Dark` give the most visual distinction between headings, body text, and inline code. If Markdown looks flat, try switching theme before reaching for settings overrides.

5. Font

A good coding font makes a real difference. Some options:

Font Price Character
JetBrains Mono Free Best all-rounder, 143 ligatures, excellent on Retina
Geist Mono Free Minimal, clean, no ligatures, "invisible" font
Berkeley Mono $75 one-time Premium craftsmanship, worth it if you live in an editor

After installing, add to settings:

{
  "buffer_font_family": "JetBrains Mono",
  "buffer_font_size": 14,
  "buffer_font_features": { "calt": true }
}

User settings: ~/.config/zed/settings.json, open with ⌘, Project settings: .zed/settings.json at repo root. Auto-loaded per project, merged with user settings. Great for per-repo formatter config, language server overrides, or exclusions.

{
  "base_keymap": "VSCode",
  "diff_view_style": "unified",
  "theme": {
    "mode": "system",
    "light": "One Light",
    "dark": "One Dark"
  },
  "buffer_font_family": "JetBrains Mono",
  "buffer_font_size": 14,
  "buffer_font_features": { "calt": true },
  "ui_font_size": 14,
  "soft_wrap": "editor_width",

  "git": {
    "inline_blame": { "enabled": true, "delay_ms": 800 }
  },

  "format_on_save": "on",
  "ensure_final_newline_on_save": true,

  "terminal": {
    "font_family": "JetBrains Mono",
    "font_size": 13,
    "working_directory": "current_project_directory"
  },

  "file_scan_exclusions": [
    "**/.git",
    "**/node_modules",
    "**/.next",
    "**/dist",
    "**/.turbo"
  ],

  "show_whitespaces": "boundary",
  "scrollbar": { "show": "auto" },
  "indent_guides": { "enabled": true },

  "auto_install_extensions": {
    "colored-zed-icons-theme": true,
    "biome": true,
    "codebook": true
  },

  "languages": {
    "Markdown": {
      "language_servers": ["codebook"],
      "soft_wrap": "editor_width"
    }
  }
}

A few things worth noting in that block:

  • "theme" with "mode": "system". Follows your OS dark/light setting automatically. Much better than hardcoding "One Dark".
  • "git": { "inline_blame": ... }. inline_blame must live under the git key, not at the top level. Easy mistake, silent failure if you get it wrong.
  • auto_install_extensions. Zed installs these on first launch. No marketplace hunting needed.

Example: Biome (linting + formatting)

If you use Biome for linting and formatting, configure it per-language rather than globally (to avoid it interfering with languages it doesn't support):

{
  "languages": {
    "TypeScript": {
      "language_servers": ["biome", "!vtsls", "!typescript-language-server"],
      "formatter": { "language_server": { "name": "biome" } },
      "code_actions_on_format": {
        "source.fixAll.biome": true,
        "source.organizeImports.biome": true
      }
    },
    "TSX": {
      "language_servers": ["biome", "!vtsls"],
      "formatter": { "language_server": { "name": "biome" } },
      "code_actions_on_format": {
        "source.fixAll.biome": true,
        "source.organizeImports.biome": true
      }
    },
    "JavaScript": {
      "language_servers": ["biome", "!vtsls"],
      "formatter": { "language_server": { "name": "biome" } },
      "code_actions_on_format": {
        "source.fixAll.biome": true,
        "source.organizeImports.biome": true
      }
    },
    "JSON": {
      "language_servers": ["biome"],
      "formatter": { "language_server": { "name": "biome" } }
    }
  }
}
Don't forget TSX. Zed treats `TypeScript` and `TSX` as separate languages. If you only configure `TypeScript`, your `.tsx` files still get formatted by vtsls. Both need the Biome override.

Requires Biome v2+. Full setup guide: biomejs.dev/reference/zed

TypeScript inlay hints (vtsls)

If you're using vtsls (the default TypeScript server), it's worth enabling inlay hints. They show parameter names and return types inline, without hovering:

{
  "lsp": {
    "vtsls": {
      "settings": {
        "typescript": {
          "inlayHints": {
            "parameterNames": { "enabled": "literals" },
            "returnTypes": { "enabled": true }
          },
          "tsserver": {
            "maxTsServerMemory": 8192
          }
        }
      }
    }
  }
}

"literals" shows parameter names only when the argument is a literal value (string, number, boolean). Low noise, high signal. maxTsServerMemory is worth bumping on large monorepos; the default is 3072MB.

7. Git integration

This is where Zed stands out from most editors.

Git panel: ⌃G shows all changed files with status indicators, staged/unstaged sections, and a commit message box.

Project diff: ⌘⇧D opens every changed file in a single split-diff multibuffer (like a github PR). You can edit directly in the diff, stage individual hunks with a click, and navigate across file boundaries without switching tabs. This is the closest equivalent to Windsurf/Cursor's diff review flow.

Split vs unified diff: Zed ships with split diff as default; I prefer unified, easy to set "diff_view_style": "unified" in settings, or toggle on the fly with Command Palette → diff: toggle split diff.

Git graph: Command Palette → git: graph for a lazy-loading, searchable commit history with a commit info panel.

Inline blame: Shows on the current line after a short delay. Toggle with ⌘K ⌘I.

Branch switching: ⌘K ⌘B or Command Palette → git: switch

Worktrees: Supported natively. Command Palette → git: create worktree. Each worktree gets its own project panel context.

Multiple repos in one window: Zed's git panel doesn't fully support workspaces with multiple git repositories yet (#52191). The workaround: use Command Palette → project: add folder to project for each sub-repo. They appear in the file tree, and you can select between them in the git panel tab, not perfect, but functional.

Docs: zed.dev/docs/git

8. AI agents. Claude Code, OpenCode, and Zed's built-in agent

Zed runs external agents via ACP (Agent Client Protocol). It works well, where agent runs as an independent process with its own thread. You can run multiple agents simultaneously on different tasks.

Open the Agent Panel: ⌘?

Panel layout: Zed's default puts the agent panel and threads on the left, project/git panel on the right. Right-click any panel icon in the status bar to move it. Or set in settings:

{
  "agent": {
    "dock": "right",
    "play_sound_when_agent_done": "always"
  }
}

"play_sound_when_agent_done": "always" is surprisingly handy. Pings you to come back when it's done.

You can also wire up both agents via settings, so they're available immediately after forking and installing:

{
  "agent_servers": {
    "opencode": { "type": "registry" },
    "claude-acp": {
      "type": "registry",
      "default_config_options": {
        "mode": "acceptEdits",
        "model": "sonnet"
      }
    }
  }
}

acceptEdits means Claude Code auto-accepts its own edits without a confirmation step on every file, swap to plan mode if you want no edits. "model": "sonnet" keeps costs reasonable; switch to "opus" with /model as needed, I find sonnet to be enough most of the time.

Claude Code (via ACP)

Command Palette → "acp: open registry" → claude-acp → Install
Agent Panel → + → claude-acp → /login (first time)

CLAUDE.md files in your repo are picked up automatically. Billing goes through your Anthropic account.

→ zed.dev/acp/agent/claude-agent

OpenCode (via ACP)

Command Palette → "acp: open registry" → OpenCode → Install
Agent Panel → + → OpenCode

OpenCode manages its own auth and model selection and supports 75+ LLM providers. Can also run as a raw TUI in the integrated terminal.

→ zed.dev/acp/agent/opencode

Reviewing agent diffs

When an agent makes changes, Zed shows them in the same editable multibuffer diff view as git. You can accept/reject individual hunks inline, or edit the diff directly before accepting.

Zed's built-in agent

Zed has a first-party agent (your choice of model: Claude, GPT, Gemini, local). Good for inline assist and quick questions.

  • Inline assist: ⌘I → applies changes inline at the cursor
  • Agent thread: ⌘? → new thread. Full conversation with file context

For autonomous multi-file work, Claude Code or OpenCode via ACP are the better choice.

Docs: zed.dev/docs/ai/external-agents

9. Keyboard shortcuts

VS Code shortcuts that carry over (with "base_keymap": "VSCode")

Action Shortcut
Command Palette ⌘⇧P
Quick open file ⌘P
Open settings ⌘,
Toggle terminal ⌘`
Go to definition F12
Peek definition ⌥F12
Find in files ⌘⇧F
Multi-cursor select next ⌘D
Move line up/down ⌥↑ / ⌥↓
Duplicate line ⌥⇧↓
Delete line ⌘⇧K
Toggle comment ⌘/
Format document ⌥⇧F
Rename symbol F2
Close tab ⌘W

Zed-specific shortcuts to learn

Action Shortcut
Open git panel ⌃G
Project diff (all changes) ⌘⇧D
Toggle inline blame ⌘K ⌘I
Switch theme ⌘K ⌘T
Open agent panel ⌘?
Inline AI assist ⌘I
Open extensions ⌘⇧X
Open keymap editor ⌘K ⌘S
Toggle project panel ⌘B
Split editor right ⌘K ⌘→
Open recent projects ⌘⌥O
Toggle word wrap ⌥Z
Open Markdown preview ⌘⇧P (in a .md file)

Shortcuts that changed

Action VS Code Zed
Open recent ⌃R ⌘⌥O
Go to symbol ⌘⇧O ⌘⇧O
Outline panel Explorer sidebar Command Palette → outline panel
Full cheat sheet: cheatsheets.zip/zed
Keybindings docs: zed.dev/docs/key-bindings
Official VS Code migration guide: zed.dev/docs/migrate/vs-code

10. Tips & tricks

Moving panels

Easy to miss, if you don't look for it. You can right-click any panel icon in the bottom status bar and tell it where to go. Zed writes the setting to your settings.json automatically. Alternatively set it manually:

{
  "project_panel": { "dock": "left" },
  "git_panel": { "dock": "left" },
  "agent": { "dock": "right" },
  "terminal": { "dock": "bottom" }
}

Opening files in an external app with a single keypress

Useful when you want to open a specific file type in a dedicated app.

Yes you can use markdown preview with ⌘P, but I like WYSIWYG markdown, so have setup Typora. Same idea works for opening a CSV in TablePlus, or an image in Preview etc

Step 1. Define the task in `~/.config/zed/tasks.json`

[
  {
    "label": "Open in Typora",
    "command": "open -a Typora \"$ZED_FILE\"",
    "reveal": "never",
    "allow_concurrent_runs": true
  }
]

$ZED_FILE is the absolute path to the currently focused file.

Gotcha: Put the full command in `command`, don't wrap it in `sh -c` with an `args` array. Zed already runs the command inside `zsh -i -c '...'`; the `args` field doesn't pass through as expected and silently does nothing.

Step 2. Bind a key in `~/.config/zed/keymap.json`:

[
  {
    "context": "Editor",
    "bindings": {
      "cmd-shift-t": ["task::Spawn", { "task_name": "Open in Typora" }]
    }
  }
]
Gotcha 1: Use `task_name`, not `task_label`. With `task_label` the task picker opens (pre-filtered but still requiring Enter). With `task_name` it runs immediately.
Gotcha 2: Use `"context": "Editor"`, not `"Workspace"`. This ensures a file is focused (so `$ZED_FILE` is populated) and avoids conflicting with Zed's default `cmd-shift-t` binding.

Same pattern works for any app just change the label, app name, and key binding.

Markdown heading contrast booster - theme override

If headings look too flat in your theme, you can boost specific Markdown tokens without switching theme globally:

{
  "languages": {
    "Markdown": {
      "theme_overrides": {
        "syntax": {
          "title": {
            "color": "#e5c07b",
            "font_weight": 700
          },
          "emphasis.strong": {
            "font_weight": 800
          },
          "emphasis": {
            "font_style": "italic"
          }
        }
      }
    }
  }
}

Adjust `#e5c07b` to taste. `title` is the Tree-sitter token for headings.

Autocomplete noise in Markdown files

A common frustration: Zed's autocomplete fires constantly while writing prose. Disable it for Markdown:

{
  "languages": {
    "Markdown": {
      "show_completions_on_input": false
    }
  }
}

11. Things you'll miss / workarounds

What you had Zed situation Workaround
Peacock window tinting Not built in Set "theme" per repo in .zed/settings.json
Settings Sync Not in Zed yet Fork my-zed-config and run install.sh, it symlinks + git gives you version-controlled config (see section 12)
WYSIWYG Markdown (vscode-office / Obsidian-style) Not supported in editor Typora alongside Zed; or use the preview pane
Markdown PDF export No built-in export Typora; or pandoc CLI
Markdown ⌘B bold shortcut Not implemented Open feature request; use Typora for heavy doc editing
Extension marketplace breadth Smaller ecosystem Most critical extensions exist; gaps closing fast
Multi-root git panel Partial support only (#52191) project: add folder to project for each sub-repo, selectable in the git panel tab
Resource URL
Starter config (fork this) github.com/a-c-m/my-zed-config
Download zed.dev/download
Official docs zed.dev/docs
VS Code migration guide zed.dev/docs/migrate/vs-code
Extensions browser zed.dev/extensions
Theme previews zed-themes.com
Theme builder zed.dev/theme-builder
Git docs zed.dev/docs/git
External agents (ACP) zed.dev/docs/ai/external-agents
ACP registry zed.dev/acp
Claude Agent zed.dev/acp/agent/claude-agent
OpenCode Agent zed.dev/acp/agent/opencode
Keybindings docs zed.dev/docs/key-bindings
Keyboard cheat sheet cheatsheets.zip/zed
Biome extension zed.dev/extensions/biome
Biome setup guide biomejs.dev/reference/zed
GitHub repo github.com/zed-industries/zed
Multi-root git tracking issue github.com/zed-industries/zed/discussions/52191

Looking for more advice / guidance / support / mentorship ?

Please take a look at my Technology Consulting service, I might be able to help.