Introduction to Zed Task Running
Zed is a high-performance, multiplayer code editor built in Rust by the creators of Atom. One of its most powerful productivity features is the built-in task running system, which lets you define, execute, and iterate on project-specific commands directly from the editor. Instead of context-switching to a terminal or relying on external task runners, Zed brings task execution into your editing workflow with first-class support.
This guide covers everything you need to know about Zed's task running system: what it is, why it matters, how to configure and run tasks, and the best practices that will keep your workflow fast and predictable.
What Is Zed Task Running?
Zed's task running system allows you to define reusable commands in a JSON configuration file and execute them on demand from within the editor. Tasks can run shell commands, scripts, build tools, test runners, linters, formatters, or any executable available on your system. Each task is identified by a unique label and can include environment variables, arguments, and command specifications.
Tasks are defined in a file named tasks.json, which can live at the project root or in a .zed directory. Zed also supports global tasks defined in your user configuration directory, which are available across all projects.
Core Concepts
- Task Definition: A JSON object describing a command, its label, and optional metadata.
- Task Runner: The built-in mechanism that executes the command and streams output to a panel.
- Task Variables: Dynamic placeholders like
$ZED_FILEor$ZED_ROWthat inject editor context into your commands. - Task Templates: Reusable task definitions that can be customized per project or language.
Why Task Running Matters
Modern development workflows involve repetitive commands: building a project, running tests, starting a dev server, linting code, or deploying. Managing these commands manually leads to friction, inconsistency, and onboarding overhead. Zed's task running system addresses these problems directly.
Key Benefits
- Reduced Context Switching: Run commands without leaving the editor or opening a separate terminal pane.
- Project Portability: Commit
tasks.jsonto version control so every contributor has the same commands available. - Consistency: Eliminate "works on my machine" issues by standardizing how commands are invoked.
- Speed: Trigger tasks with keyboard shortcuts and see output instantly in an integrated panel.
- Editor Integration: Use variables like the current file path or selection to build context-aware commands.
How to Use Zed Task Running
Creating Your First Task File
To get started, create a file named tasks.json in the root of your project. Zed will automatically detect this file and make its tasks available through the task runner. The file contains a JSON array of task objects.
[
{
"label": "Build Project",
"command": "npm",
"args": ["run", "build"],
"env": {
"NODE_ENV": "production"
}
},
{
"label": "Run Dev Server",
"command": "npm",
"args": ["run", "dev"]
}
]
In this example, two tasks are defined. The first builds the project with production environment variables, and the second starts a development server. Each task has a label that appears in the task picker, a command to execute, and optional args and env fields.
Running a Task
Once your tasks.json file is in place, you can run tasks using the command palette or a keyboard shortcut. Open the command palette with cmd-shift-p (macOS) or ctrl-shift-p (Linux), type "task", and select "task: spawn". Zed will present a list of available tasks. Select one to execute it.
The output of the task appears in a dedicated panel at the bottom of the editor. You can scroll through the output, copy text, and close the panel when you are done. If a task is long-running, such as a dev server, the panel will continue streaming output until you stop the task manually.
Using Task Variables
One of the most powerful features of Zed tasks is the ability to inject editor context using variables. These variables are resolved at runtime and allow you to build commands that adapt to what you are currently working on.
[
{
"label": "Run Current File",
"command": "node",
"args": ["$ZED_FILE"]
},
{
"label": "Lint Current File",
"command": "npx",
"args": ["eslint", "$ZED_FILE"]
},
{
"label": "Open File at Cursor Line",
"command": "echo",
"args": ["File: $ZED_FILE, Row: $ZED_ROW, Column: $ZED_COLUMN"]
}
]
The available variables include the current file path, the cursor's row and column, the selected text, and the project root directory. These variables make it easy to create tasks that operate on the file you are editing without hardcoding paths.
Common Task Variables
$ZED_FILE— The absolute path of the currently active file.$ZED_FILENAME— The filename without the directory path.$ZED_DIRNAME— The directory containing the current file.$ZED_ROW— The current cursor row (1-indexed).$ZED_COLUMN— The current cursor column (1-indexed).$ZED_SELECTION— The currently selected text.$ZED_WORKTREE_ROOT— The root directory of the current worktree.
Working with Multiple Task Files
Zed supports multiple layers of task configuration. You can define global tasks that are available in every project, project-level tasks that are shared with your team, and local tasks that are specific to your machine. This layered approach gives you flexibility without sacrificing consistency.
Global tasks are stored in ~/.config/zed/tasks.json on Linux or ~/Library/Application Support/Zed/tasks.json on macOS. Project tasks live in .zed/tasks.json or tasks.json at the project root. When you spawn a task, Zed merges all available task definitions and presents them in a single list.
[
{
"label": "Global: Git Status",
"command": "git",
"args": ["status"]
},
{
"label": "Global: Open Project in Browser",
"command": "open",
"args": ["http://localhost:3000"]
}
]
Task Templates for Languages
Zed also supports language-specific task templates. These are predefined tasks that Zed generates based on the language of the current file. For example, if you are editing a Python file, Zed can offer a template task to run the file with python3. If you are editing a Rust file, it can offer cargo run.
You can customize these templates by defining your own tasks with the same labels, which will override the defaults. This is useful when you need to pass specific flags or environment variables that the default templates do not include.
[
{
"label": "Python: Run with Debug",
"command": "python3",
"args": ["-u", "$ZED_FILE"],
"env": {
"PYTHONPATH": "$ZED_WORKTREE_ROOT/src"
}
}
]
Running Tasks in the Background
Some tasks, like file watchers or dev servers, are meant to run continuously in the background. Zed handles these gracefully by keeping the output panel open and streaming output as it arrives. You can continue editing while the task runs, and you can stop it at any time using the stop button in the output panel.
[
{
"label": "Watch CSS",
"command": "npx",
"args": ["tailwindcss", "-i", "./src/input.css", "-o", "./dist/output.css", "--watch"]
},
{
"label": "Start API Server",
"command": "python3",
"args": ["-m", "uvicorn", "main:app", "--reload"],
"env": {
"DATABASE_URL": "postgresql://localhost/myapp"
}
}
]
Chaining and Combining Commands
While Zed tasks execute a single command, you can chain multiple commands using shell syntax. Since Zed runs commands through your system shell, you can use operators like &&, ||, and pipes to combine steps into a single task.
[
{
"label": "Lint and Test",
"command": "npm run lint && npm test"
},
{
"label": "Format and Commit",
"command": "npx prettier --write . && git add -A && git commit -m 'auto-format'"
},
{
"label": "Build and Deploy",
"command": "npm run build && rsync -avz dist/ user@server:/var/www/app/"
}
]
Note that when using shell operators, you should pass the entire command string as the command field rather than splitting it into args. Zed will execute the string through your shell, which interprets the operators correctly.
Best Practices
Commit Your tasks.json to Version Control
Your tasks.json file should be committed to your repository so that every team member has access to the same set of commands. This ensures consistency and reduces onboarding time for new contributors. If you have machine-specific tasks, such as opening a local browser or connecting to a local database, define those in your global task file instead.
Use Descriptive Labels
Task labels are the primary way you and your teammates identify tasks in the picker. Use clear, descriptive names that indicate what the task does. Prefix related tasks with a category, such as "Test:" or "Build:", to keep the list organized as it grows.
[
{
"label": "Test: Run All",
"command": "npm",
"args": ["test"]
},
{
"label": "Test: Run Watch Mode",
"command": "npm",
"args": ["test", "--", "--watch"]
},
{
"label": "Test: Coverage Report",
"command": "npm",
"args": ["test", "--", "--coverage"]
}
]
Leverage Environment Variables
Use the env field to set environment variables for your tasks rather than embedding them in the command string. This keeps your task definitions clean and makes it easy to adjust configuration without modifying the command itself. It also prevents sensitive values from being visible in process listings.
[
{
"label": "Run Migrations",
"command": "npx",
"args": ["prisma", "migrate", "deploy"],
"env": {
"DATABASE_URL": "postgresql://localhost:5432/myapp"
}
}
]
Keep Tasks Focused
Each task should do one thing well. Avoid creating monolithic tasks that build, test, lint, and deploy in a single command. Instead, create separate tasks for each step and chain them manually when needed. This makes it easier to debug failures and reuse individual steps in different contexts.
Use Variables for Portability
Always prefer task variables like $ZED_FILE and $ZED_WORKTREE_ROOT over hardcoded paths. This makes your tasks portable across different machines and directory structures. A task that references /home/user/projects/myapp/src/index.ts will only work on one machine, but a task that references $ZED_FILE works everywhere.
Document Complex Tasks
If a task involves non-obvious steps or configuration, add a comment or documentation in your project's README explaining what it does and when to use it. While Zed does not currently support inline comments in tasks.json (since JSON does not natively support comments), you can use a tasks.jsonc file if you prefer JSON with comments, or document tasks in your project wiki.
Conclusion
Zed's task running system is a lightweight yet powerful feature that streamlines your development workflow by bringing command execution directly into the editor. By defining tasks in a version-controlled tasks.json file, leveraging editor variables for context-aware commands, and following best practices around naming, environment configuration, and task granularity, you can eliminate repetitive context switching and create a consistent, shareable workflow for your entire team. Whether you are running a quick test on the current file or starting a complex multi-service development environment, Zed tasks provide the speed and flexibility to keep you focused on writing code.