Editors
Zed
Zed starts vtsls, a TypeScript server, for every JavaScript file, and it reads
a Flow file as TypeScript. A project's own .zed/settings.json can
drop vtsls for that project and put uf in its place, both as the language
server and as the formatter.
What you will be able to do: open a uf project in Zed and get uf's diagnostics, hover, definitions, completion, quick fixes and formatting, without vtsls's errors on Flow syntax.
What you need first: uf installed, a project with a
uf.config.js, and Rust installed through rustup (Zed compiles a dev
extension itself).
1. Install the extension
Zed has no setting that adds a language server of your own. A server has to
come from an extension, so uf's lives in
editors/zed.
It is not in Zed's extension registry yet, so install it as a dev extension.
uf editor install zed writes its sources to ~/.local/share/uf/editors/zed
(under $XDG_DATA_HOME when that is set). Zed has no command-line install, so
then open the command palette, run zed: install dev extension, and select
that directory, or editors/zed in a uf checkout.
The extension starts uf lsp --cwd <worktree>, using the project's
node_modules/.bin/uf before one on PATH. lsp.uf.binary.path in Zed's
settings overrides both. It serves only a worktree with uf.config.js at its
root. Zed's defaults ask every JavaScript server in every JavaScript project,
so in a project without that file the extension declines, with a message
saying why.
2. Keep vtsls off this project
uf editor setup zed writes this, keeping anything the project's file already
says. By hand, commit it as .zed/settings.json in the project:
{
"languages": {
"JavaScript": {
"language_servers": ["uf", "!vtsls", "!typescript-language-server", "..."],
"formatter": { "language_server": { "name": "uf" } },
"format_on_save": "on"
}
}
}
language_servers:"uf"turns uf on,"!name"turns a server off, and"..."means every other server registered for the language, so ESLint and Tailwind keep running if the project uses them. Zed's default for JavaScript is["!typescript-language-server", "vtsls", "..."].- Zed's JavaScript is
.js,.jsx,.mjsand.cjs..jsxis not TSX, so this one block covers every file uf reads. formatternames uf explicitly. With the default"auto", Zed would pick Prettier for JavaScript.format_on_saveis"off"by default.- A project's list replaces your user list. Lists in Zed's settings do not merge. That is what makes this per project: a TypeScript project opened in the same Zed still gets vtsls from the defaults.
To stop Zed asking the uf extension in projects that are not uf projects at
all, add "!uf" to languages.JavaScript.language_servers in your user
settings. The project's list above names "uf" and wins.
3. Trust the project
Zed's worktree trust (restricted mode) does not start language servers that a
project's .zed/settings.json asks for until you trust the project. Trust it
when Zed asks, or from the restricted-mode banner.
4. Check that it worked
- Open a file with
componentormatch. The diagnostics panel lists onlyufandflowentries. - The language server menu in the status bar lists
uffor the buffer and notvtsls. - Save a file, then run
uf fmt --checkin a terminal. If it reports the file, Zed opened a different folder than the one that holdsuf.config.js.
Editing uf.config.js needs editor: restart language server, because the
server reads it once, at start-up.
What Zed does not get
Zed highlights JavaScript with a tree-sitter grammar that does not know
component, hook, match or renders. No maintained tree-sitter grammar
for modern Flow exists to ship instead, so those lines are highlighted as the
JavaScript grammar parses them. The language features come from uf and are
unaffected.
Checked against
The setting syntax, the defaults, the merge behaviour and worktree trust were
read from Zed's documentation and source (assets/settings/default.json, the
settings merge, trusted_worktrees) in September 2026. CI tests the extension's
decisions on the host and builds its WebAssembly. No Zed runs in CI.
Edit this pagedocs/app/guide/editors/zed/$page.mdx