Introduction to Zed Code Snippets
Zed is a high-performance, multiplayer code editor built in Rust by the creators of Atom. One of its most powerful productivity features is code snippets — reusable templates that expand into structured code blocks with placeholders. Snippets help you write boilerplate faster, maintain consistency across your codebase, and reduce the cognitive load of remembering repetitive syntax.
In this guide, we'll cover everything you need to know about Zed snippets: what they are, why they matter, how to create and use them, and the best practices that will make you a more efficient developer.
What Are Zed Code Snippets?
A snippet is a short keyword that, when typed and triggered, expands into a larger block of code. Snippets can include tab-stops (placeholders) that let you jump between editable fields using the Tab key, allowing you to fill in variable names, values, and logic without ever touching your mouse.
Zed's snippet engine is heavily inspired by the TextMate snippet syntax, which is also used by VS Code. This means snippets are defined in JSON files and support features like placeholders, choices, variables, and transformations.
Snippet Anatomy
At its core, a Zed snippet consists of three parts:
- Prefix — the trigger keyword you type to invoke the snippet.
- Body — the actual code that gets inserted, which may contain tab-stops and placeholders.
- Description — an optional human-readable label shown in autocomplete menus.
Why Snippets Matter
Snippets are more than a convenience — they are a meaningful productivity multiplier. Here's why they matter:
- Speed: Reduce keystrokes for repetitive structures like function definitions, class templates, or test scaffolds.
- Consistency: Enforce team-wide coding standards by sharing snippet files in version control.
- Accuracy: Eliminate typos in boilerplate by generating syntactically correct code every time.
- Focus: Stay in flow by minimizing context switches and reducing manual typing.
- Onboarding: New team members can ramp up faster by using shared snippets that encode common patterns.
How to Use Snippets in Zed
Triggering a Snippet
Zed ships with built-in snippets for many languages. To use one, simply type its prefix in a supported file and press Tab when the autocomplete suggestion appears. For example, in a JavaScript file, typing clg and pressing Tab expands into console.log() with the cursor placed inside the parentheses.
Once a snippet is inserted, you can navigate between placeholders using Tab (forward) and Shift+Tab (backward). Pressing Esc exits snippet mode and places the cursor at the final tab-stop.
Creating Custom Snippets
Zed stores user snippets in JSON files inside your configuration directory. The path depends on your operating system:
- macOS:
~/.config/zed/snippets/ - Linux:
~/.config/zed/snippets/ - Windows:
%APPDATA%\Zed\snippets\
Each file is named after the language it targets, such as javascript.json, python.json, or rust.json. You can also create a global.json file for snippets available across all languages.
Here is a basic example of a custom JavaScript snippet file:
{
"Function Declaration": {
"prefix": "fn",
"body": [
"function ${1:name}(${2:params}) {",
" ${0:// body}",
"}"
],
"description": "Create a named function declaration"
},
"Arrow Function": {
"prefix": "afn",
"body": [
"const ${1:name} = (${2:params}) => {",
" ${0:// body}",
"}"
],
"description": "Create an arrow function"
}
}
After saving this file, the snippets are immediately available — no restart required. Type fn in a JavaScript file, press Tab, and the function template appears with your cursor at the name placeholder.
Understanding Tab-Stops and Placeholders
The body of a snippet uses special syntax to define interactive elements:
$1,$2,$3— numbered tab-stops. The cursor jumps to each in order when you pressTab.$0— the final cursor position. This is where the cursor lands after the last tab-stop.${1:default}— a tab-stop with placeholder text that is pre-selected and can be overwritten.${1|option1,option2,option3|}— a choice placeholder that presents a dropdown of options.
Here is a more advanced example demonstrating these features in a React component snippet:
{
"React Component": {
"prefix": "rc",
"body": [
"import React from 'react';",
"",
"export const ${1:ComponentName} = ({ ${2:children} }) => {",
" return (",
" ",
" {${2:children}}",
" ",
" );",
"};"
],
"description": "Create a functional React component"
},
"Use State Hook": {
"prefix": "ustate",
"body": [
"const [${1:state}, set${1/(.*)/${1:/capitalize}/}] = useState(${2:initialValue});"
],
"description": "Create a useState hook with setter"
}
}
Notice the transformation in the second snippet: ${1/(.*)/${1:/capitalize}/} takes the value you type for the state variable and automatically capitalizes it for the setter function name. So if you type count, the setter becomes setCount.
Using Variables
Zed snippets support built-in variables that insert context-aware values automatically. Common variables include:
$TM_FILENAME— the current file name.$TM_FILENAME_BASE— the file name without extension.$TM_DIRECTORY— the directory of the current file.$TM_FILEPATH— the full file path.$TM_CURRENT_LINE— the contents of the current line.$TM_SELECTED_TEXT— the currently selected text.$CLIPBOARD— the contents of the clipboard.
Here is a Python snippet that uses the file name to generate a class definition:
{
"Python Class": {
"prefix": "cls",
"body": [
"class ${1:${TM_FILENAME_BASE/(.*)/${1:/capitalize}/}}:",
" \"\"\"${2:Docstring for the class}.\"\"\"",
"",
" def __init__(self${3:, *args, **kwargs}):",
" super().__init__(*args, **kwargs)",
" ${0:pass}"
],
"description": "Create a Python class based on file name"
}
}
If you create a file called user_account.py and trigger this snippet, the class name will be pre-filled as User_account, ready for you to refine.
Snippet Scope and Language Targeting
Snippets are scoped by the file they live in. A snippet defined in rust.json only appears in Rust files. This prevents clutter and ensures relevant suggestions are surfaced. If you want a snippet available everywhere, place it in global.json.
Here is an example rust.json with several useful Rust snippets:
{
"Test Function": {
"prefix": "tfn",
"body": [
"#[test]",
"fn ${1:test_name}() {",
" ${0:assert!(true);}",
"}"
],
"description": "Create a test function"
},
"Derive Debug": {
"prefix": "ddebug",
"body": [
"#[derive(Debug)]"
],
"description": "Insert derive Debug attribute"
},
"Match Statement": {
"prefix": "match",
"body": [
"match ${1:value} {",
" ${2:pattern} => ${3:outcome},",
" _ => ${0:todo!()},",
"}"
],
"description": "Create a match expression"
},
"Impl Block": {
"prefix": "impl",
"body": [
"impl ${1:Type} {",
" ${0:// methods}",
"}"
],
"description": "Create an impl block"
}
}
Multi-Cursor Snippets
One of Zed's standout features is its native multi-cursor support, which extends to snippets. If you place the same numbered tab-stop in multiple locations within a snippet body, all instances are selected simultaneously when you reach that tab-stop. Editing one edits them all.
{
"HTML Tag": {
"prefix": "tag",
"body": [
"<${1:div}>",
" ${0}",
"${1:div}>"
],
"description": "Create an HTML tag with matching closing tag"
}
}
In this example, when you type the tag name at the first tab-stop, both the opening and closing tags update in real time.
Best Practices
Choose Intuitive Prefixes
Pick prefixes that are short, memorable, and unlikely to collide with common words. Prefixes like fn, cls, ifel, and clg are easy to remember and quick to type. Avoid prefixes that are common identifiers in your language to prevent unwanted expansions.
Write Clear Descriptions
Always include a description. When multiple snippets share similar prefixes, the description helps you pick the right one from the autocomplete menu. Descriptions also help teammates understand what a snippet does without reading the body.
Use the Final Tab-Stop Wisely
Always define $0 as the final cursor position. Without it, the cursor remains at the last numbered tab-stop, which can be disorienting. Place $0 where you most naturally want to continue writing code after the snippet is filled in.
Share Snippets with Your Team
Commit your snippet files to your project repository or a shared dotfiles repo. This ensures every developer benefits from the same shortcuts and coding patterns. Consider organizing snippets by domain — for example, react.json, testing.json, and database.json — so they are easy to find and maintain.
Keep Snippets DRY
If you find yourself writing the same logic in multiple snippets, consider breaking it into smaller, composable snippets. For example, instead of one massive snippet for a full API route handler, create separate snippets for the route signature, the validation logic, and the response formatting. This gives you flexibility to mix and match.
Test Snippets Before Sharing
Always trigger a snippet in a real file before sharing it with your team. Verify that tab-stops are in the right order, placeholders have sensible defaults, and transformations produce the expected output. A broken snippet is worse than no snippet at all.
Version Your Snippets
As your codebase evolves, your snippets should too. Treat snippet files like code — review changes, update them when patterns shift, and remove obsolete ones. Stale snippets that generate outdated patterns can introduce bugs and confusion.
Conclusion
Zed code snippets are a deceptively simple feature with outsized impact on your daily workflow. By investing a small amount of time upfront to define the templates you use most often, you can dramatically reduce repetitive typing, enforce consistency across your projects, and keep your focus where it belongs — on solving real problems. Start with a handful of snippets for your most common patterns, share them with your team, and iterate over time. The more you integrate snippets into your muscle memory, the more natural and powerful they become.