Zed tasks and keybindings: turning your editor into a workflow runner
Published 2025-12-12 by Owner
Zed has a tasks system that lets you bind shell commands to keystrokes. Once configured, common workflows become muscle memory.
The basics
Tasks live in .zed/tasks.json (project-specific) or your user config (global):
[
{
"label": "Run tests",
"command": "bun test",
"args": [],
"cwd": "$ZED_WORKTREE_ROOT"
},
{
"label": "Format file",
"command": "biome",
"args": ["format", "--write", "$ZED_FILE"],
"cwd": "$ZED_WORKTREE_ROOT"
}
]
Each task has a label, command, and args. Variables like $ZED_FILE and $ZED_WORKTREE_ROOT interpolate.
Binding to keys
In .zed/keymap.json:
[
{
"context": "Workspace",
"bindings": {
"cmd-shift-t": ["task::Spawn", { "label": "Run tests" }],
"cmd-shift-f": ["task::Spawn", { "label": "Format file" }]
}
}
]
Now Cmd+Shift+T runs tests. Cmd+Shift+F formats. No mouse, no menu navigation.
Tasks I’ve found useful
A few I use daily:
Run current test file:
{
"label": "Test current file",
"command": "bun test $ZED_FILE",
"cwd": "$ZED_WORKTREE_ROOT"
}
Run tests for the current package (in a monorepo):
{
"label": "Test current package",
"command": "bun test",
"cwd": "$ZED_DIRNAME"
}
Format and lint the current file:
{
"label": "Lint current",
"command": "biome check --apply $ZED_FILE",
"cwd": "$ZED_WORKTREE_ROOT"
}
Generate types from schema:
{
"label": "Generate types",
"command": "bun run codegen",
"cwd": "$ZED_WORKTREE_ROOT"
}
Comparison to other editors
VS Code has tasks; the configuration is similar in spirit but more verbose. JetBrains has run configurations; more powerful but heavier.
Zed’s tasks are simple. The configuration is minimal. The friction to add a task is low.
A pattern that emerged
After a few months, my tasks fell into categories:
Hot tasks (multiple times per hour): test, format, type-check. These get keybindings.
Warm tasks (once per session): build, deploy preview, generate. These I invoke from the command palette.
Cold tasks (rarely): clean, full reset, etc. These I run from terminal directly.
The keybinding budget is finite (good keys are scarce). Reserve them for hot tasks. Use the palette for the rest.
Per-project vs global
Some tasks make sense globally (format, test). Some are project-specific (deploy this project, generate types for this schema).
Zed supports both. Global tasks live in your user config. Project tasks live in .zed/tasks.json.
The pattern: global tasks for things that work the same across all projects. Project tasks for project-specific commands.
With Zed’s AI
Zed’s AI panel can also trigger tasks via slash commands:
/run-task Test current file
This is useful for AI-driven workflows where you want the AI to verify its changes:
> Make this function use Result<T> instead of throwing.
> /run-task Type-check current
> /run-task Test current file
The AI executes; the tasks verify; the loop closes.
Worth setting up?
For Zed users who haven’t customized: yes. The setup is 30 minutes; the payoff is years.
For Zed users with sparse customization: still worth it. Even 3-4 keybindings for common tasks compound over time.
For users on other editors: the pattern transfers. Whether your editor has the same simplicity varies.
What I’d skip
A few patterns I’ve found unhelpful:
Tasks for things shells handle. cd ~/projects doesn’t need to be a task; it’s two characters in any shell.
Tasks I run rarely. If I run something monthly, the time to find the task takes longer than typing the command.
Tasks with complex argument prompting. Zed’s task system isn’t great at “ask me which test file to run.” For these, I drop to terminal.
Closing
Zed’s tasks system is a small feature that compounds over time. The setup investment is bounded; the daily benefit accumulates.
For users wanting to optimize their Zed workflow, this is one of the higher-leverage configurations. The tasks become muscle memory; the keystrokes save real time.
Pair with vim mode and AI panel; the result is an editor where you stay on keyboard for almost everything. Worth the setup.