1---
2title: Rust
3description: "Configure Rust language support in Zed, including language servers, formatting, and debugging."
4---
5
6# Rust
7
8Rust support is available natively in Zed.
9
10- Tree-sitter: [tree-sitter/tree-sitter-rust](https://github.com/tree-sitter/tree-sitter-rust)
11- Language Server: [rust-lang/rust-analyzer](https://github.com/rust-lang/rust-analyzer)
12- Debug Adapter: [CodeLLDB](https://github.com/vadimcn/codelldb) (primary), [GDB](https://sourceware.org/gdb/) (secondary, not available on Apple silicon)
13
14<!--
15TBD: Polish Rust docs. Zed has strong Rust support, and the docs should reflect that clearly.
16TBD: Users may not know what inlayHints, don't start there.
17TBD: Provide explicit examples not just `....`
18-->
19
20## Inlay Hints
21
22The following configuration can be used to change the inlay hint settings for `rust-analyzer` in Rust:
23
24```json [settings]
25{
26 "lsp": {
27 "rust-analyzer": {
28 "initialization_options": {
29 "inlayHints": {
30 "maxLength": null,
31 "lifetimeElisionHints": {
32 "enable": "skip_trivial",
33 "useParameterNames": true
34 },
35 "closureReturnTypeHints": {
36 "enable": "always"
37 }
38 }
39 }
40 }
41 }
42}
43```
44
45See [Inlay Hints](https://rust-analyzer.github.io/book/features.html#inlay-hints) in the Rust Analyzer Manual for more information.
46
47## Target directory
48
49The `rust-analyzer` target directory can be set in `initialization_options`:
50
51```json [settings]
52{
53 "lsp": {
54 "rust-analyzer": {
55 "initialization_options": {
56 "rust": {
57 "analyzerTargetDir": true
58 }
59 }
60 }
61 }
62}
63```
64
65A `true` setting will set the target directory to `target/rust-analyzer`. You can set a custom directory with a string like `"target/analyzer"` instead of `true`.
66
67## Binary
68
69You can configure which `rust-analyzer` binary Zed should use.
70
71By default, Zed will try to find a `rust-analyzer` in your `$PATH` and try to use that. If that binary successfully executes `rust-analyzer --help`, it's used. Otherwise, Zed will fall back to installing its own stable `rust-analyzer` version and use that.
72
73If you want to install pre-release `rust-analyzer` version instead you can instruct Zed to do so by setting `pre_release` to `true` in your `settings.json`:
74
75```json [settings]
76{
77 "lsp": {
78 "rust-analyzer": {
79 "fetch": {
80 "pre_release": true
81 }
82 }
83 }
84}
85```
86
87If you want to disable Zed looking for a `rust-analyzer` binary, you can set `ignore_system_version` to `true` in your `settings.json`:
88
89```json [settings]
90{
91 "lsp": {
92 "rust-analyzer": {
93 "binary": {
94 "ignore_system_version": true
95 }
96 }
97 }
98}
99```
100
101If you want to use a binary in a custom location, you can specify a `path` and optional `arguments`:
102
103```json [settings]
104{
105 "lsp": {
106 "rust-analyzer": {
107 "binary": {
108 "path": "/Users/example/bin/rust-analyzer",
109 "arguments": []
110 }
111 }
112 }
113}
114```
115
116This `"path"` has to be an absolute path.
117
118## Alternate Targets
119
120If you want rust-analyzer to provide diagnostics for a target other than your current platform (e.g. for windows when running on macOS) you can use the following Zed lsp settings:
121
122```json [settings]
123{
124 "lsp": {
125 "rust-analyzer": {
126 "initialization_options": {
127 "cargo": {
128 "target": "x86_64-pc-windows-msvc"
129 }
130 }
131 }
132 }
133}
134```
135
136If you are using `rustup`, you can find a list of available target triples (`aarch64-apple-darwin`, `x86_64-unknown-linux-gnu`, etc) by running:
137
138```sh
139rustup target list --installed
140```
141
142## LSP tasks
143
144Zed provides tasks using tree-sitter, but rust-analyzer has an LSP extension method for querying file-related tasks via LSP.
145This is enabled by default and can be configured as
146
147```json [settings]
148"lsp": {
149 "rust-analyzer": {
150 "enable_lsp_tasks": true,
151 }
152}
153```
154
155## Manual Cargo Diagnostics fetch
156
157By default, rust-analyzer has `checkOnSave: true` enabled, which causes every buffer save to trigger a `cargo check --workspace --all-targets` command.
158If disabled with `checkOnSave: false` (see the example of the server configuration json above), it's still possible to fetch the diagnostics manually, with the `editor: run/clear/cancel flycheck` commands in Rust files to refresh cargo diagnostics; the project diagnostics editor will also refresh cargo diagnostics with `editor: run flycheck` command when the setting is enabled.
159
160## More server configuration
161
162<!--
163TBD: Is it possible to specify RUSTFLAGS? https://github.com/zed-industries/zed/issues/14334
164-->
165
166Rust-analyzer [manual](https://rust-analyzer.github.io/book/) describes various features and configuration options for rust-analyzer language server.
167Rust-analyzer in Zed runs with the default parameters.
168
169### Large projects and performance
170
171One of the main caveats that might cause extensive resource usage on large projects, is the combination of the following features:
172
173```
174rust-analyzer.checkOnSave (default: true)
175 Run the check command for diagnostics on save.
176```
177
178```
179rust-analyzer.check.workspace (default: true)
180 Whether --workspace should be passed to cargo check. If false, -p <package> will be passed instead.
181```
182
183```
184rust-analyzer.cargo.allTargets (default: true)
185 Pass --all-targets to cargo invocation
186```
187
188Which would mean that every time Zed saves, a `cargo check --workspace --all-targets` command is run, checking the entire project (workspace), lib, doc, test, bin, bench and [other targets](https://doc.rust-lang.org/cargo/reference/cargo-targets.html).
189
190While that works fine on small projects, it does not scale well.
191
192The alternatives would be to use [tasks](../tasks.md), as Zed already provides a `cargo check --workspace --all-targets` task and the ability to cmd/ctrl-click on the terminal output to navigate to the error, and limit or turn off the check on save feature entirely.
193
194Check on save feature is responsible for returning part of the diagnostics based on cargo check output, so turning it off will limit rust-analyzer with its own [diagnostics](https://rust-analyzer.github.io/book/diagnostics.html).
195
196Consider more `rust-analyzer.cargo.` and `rust-analyzer.check.` and `rust-analyzer.diagnostics.` settings from the manual for more fine-grained configuration.
197Here's a snippet for Zed settings.json (the language server will restart automatically after the `lsp.rust-analyzer` section is edited and saved):
198
199```json [settings]
200{
201 "lsp": {
202 "rust-analyzer": {
203 "initialization_options": {
204 // get more cargo-less diagnostics from rust-analyzer,
205 // which might include false-positives (those can be turned off by their names)
206 "diagnostics": {
207 "experimental": {
208 "enable": true
209 }
210 },
211 // To disable the checking entirely
212 // (ignores all cargo and check settings below)
213 "checkOnSave": false,
214 // To check the `lib` target only.
215 "cargo": {
216 "allTargets": false
217 },
218 // Use `-p` instead of `--workspace` for cargo check
219 "check": {
220 "workspace": false
221 }
222 }
223 }
224 }
225}
226```
227
228### Multi-project workspaces
229
230If you want rust-analyzer to analyze multiple Rust projects in the same folder that are not listed in `[members]` in the Cargo workspace,
231you can list them in `linkedProjects` in the local project settings:
232
233```json [settings]
234{
235 "lsp": {
236 "rust-analyzer": {
237 "initialization_options": {
238 "linkedProjects": ["./path/to/a/Cargo.toml", "./path/to/b/Cargo.toml"]
239 }
240 }
241 }
242}
243```
244
245### Snippets
246
247There's a way to get custom completion items from rust-analyzer, that will transform the code according to the snippet body:
248
249```json [settings]
250{
251 "lsp": {
252 "rust-analyzer": {
253 "initialization_options": {
254 "completion": {
255 "snippets": {
256 "custom": {
257 "Arc::new": {
258 "postfix": "arc",
259 "body": ["Arc::new(${receiver})"],
260 "requires": "std::sync::Arc",
261 "scope": "expr"
262 },
263 "Some": {
264 "postfix": "some",
265 "body": ["Some(${receiver})"],
266 "scope": "expr"
267 },
268 "Ok": {
269 "postfix": "ok",
270 "body": ["Ok(${receiver})"],
271 "scope": "expr"
272 },
273 "Rc::new": {
274 "postfix": "rc",
275 "body": ["Rc::new(${receiver})"],
276 "requires": "std::rc::Rc",
277 "scope": "expr"
278 },
279 "Box::pin": {
280 "postfix": "boxpin",
281 "body": ["Box::pin(${receiver})"],
282 "requires": "std::boxed::Box",
283 "scope": "expr"
284 },
285 "vec!": {
286 "postfix": "vec",
287 "body": ["vec![${receiver}]"],
288 "description": "vec![]",
289 "scope": "expr"
290 }
291 }
292 }
293 }
294 }
295 }
296 }
297}
298```
299
300## Debugging
301
302Zed supports debugging Rust binaries and tests out of the box with `CodeLLDB` and `GDB`. Run {#action debugger::Start} ({#kb debugger::Start}) to launch one of these preconfigured debug tasks.
303
304For more control, you can add debug configurations to `.zed/debug.json`. See the examples below.
305
306- [CodeLLDB configuration documentation](https://github.com/vadimcn/codelldb/blob/master/MANUAL.md#starting-a-new-debug-session)
307- [GDB configuration documentation](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Debugger-Adapter-Protocol.html)
308
309### Build binary then debug
310
311```json [debug]
312[
313 {
314 "label": "Build & Debug native binary",
315 "build": {
316 "command": "cargo",
317 "args": ["build"]
318 },
319 "program": "$ZED_WORKTREE_ROOT/target/debug/binary",
320 // sourceLanguages is required for CodeLLDB (not GDB) when using Rust
321 "sourceLanguages": ["rust"],
322 "request": "launch",
323 "adapter": "CodeLLDB"
324 }
325]
326```
327
328### Automatically locate a debug target based on build command
329
330When you use `cargo build` or `cargo test` as the build command, Zed can infer the path to the output binary.
331
332```json [debug]
333[
334 {
335 "label": "Build & Debug native binary",
336 "adapter": "CodeLLDB",
337 "build": {
338 "command": "cargo",
339 "args": ["build"]
340 },
341 // sourceLanguages is required for CodeLLDB (not GDB) when using Rust
342 "sourceLanguages": ["rust"]
343 }
344]
345```