Spring Boot development works in Zed now
If you use Zed and open a Java project, you hit the same wall every time. Java
itself is fine thanks to the official Java extension — but nothing knows about
Spring. application.yml is just text. Autocomplete doesn't fire inside
@Value("${...}"). A typo in the JPQL inside @Query passes in silence. So the
Spring work drifts back to IntelliJ or VS Code.
That's why I've been building
Zed Spring Tools —
an extension that brings the Spring team's own
Spring Tools language server into Zed.
Up front
This is not a stable release. Where it actually stands:
- macOS arm64 is the only environment with runtime evidence, on Temurin JDK
25.0.3 and the declared floor 21.0.11. There is Linux and Windows code in
there, but no evidence, so I don't call it supported. - It's submitted to the Zed extension registry
and awaiting review. For now you install it as a dev extension. - The official Java extension is required. This sits beside it rather than
replacing it.
The documentation follows the same rule. "Implemented" and "observed working"
are tracked as separate states, and only the second one makes the feature list.
Of 59 tracked capabilities, 46 are verified — and the "built but not yet
observed working" bucket is deliberately empty. Nothing ships on the strength of
the code existing.
What actually works
All of this has been observed on the tested environment.
Config files — completion, hover, validation, and go-to-definition for
application.properties and .yml, plus .properties ↔ .yaml conversion.
Spring-aware Java completion — property keys inside @Value, bean names
inside @Qualifier, scopes and profiles, Spring Data query methods derived from
the entity, bean-injection proposals inside @Component methods. The
@GetMapping family of method templates comes with its imports on insertion.
Queries and SpEL — syntax validation for the JPQL, HQL, or SQL inside
@Query; go-to-definition from a ?1 or :name parameter to the method
parameter it stands for; a parameter-name inlay hint on ?1. SpEL is validated
everywhere Spring reads an expression — @Value, @Cacheable,
@EventListener, @ConditionalOnExpression, and the rest — and you can jump
from a SpEL bean reference to its @Bean declaration.
Spring's analysis and quick fixes — unnecessary @Autowired, field
injection worth turning into a constructor parameter, types removed in Boot 3,
the Boot 4 API-versioning and bean-registrar checks, and more. What matters is
that the quick fixes actually rewrite your code. Hit "Convert @Autowired
field into Constructor Parameter" and it removes the field and writes the
constructor. Both of Spring's fix engines work — the JDT refactorings and the
OpenRewrite recipes. Boot patch upgrades ride the same path: the quick fix at
the top of your build file bumps the version through an edit you can inspect
before saving.
Build-file diagnostics — an available patch or minor release, whether your
Boot generation is still inside OSS or commercial support (with the dates Spring
publishes), and whether the Spring Cloud release on your classpath actually
supports that Boot generation.
Live data from a running app — a code action connects to a local Boot
process, live bean and endpoint information renders in CodeLens, and you can
dump heap, GC, and logger snapshots to .zed/spring-live.md. Logger levels can
be changed too, behind a confirmation prompt. Remote apps connect through the
boot-java.remote-apps setting — the same settings-only route VS Code uses.
Run/debug config generation — one code action discovers the Boot projects in
your worktree and writes .zed/tasks.json and .zed/debug.json. It emits one
entry per Spring profile it finds in application-<profile>.*, so Zed's task
picker becomes your profile picker. It never overwrites a config it can't parse
without loss — that gets a reviewable sidecar file instead.
Spring Modulith — the module-violation diagnostic fires on references that
reach into another module's internals, and the Structure document groups the
project by application module with each type marked (API) or (internal).
It works on a plane. Once the pinned Spring Tools artifact has been
downloaded once, nothing needs the network again. A run with every outbound
connection blocked still gave completion, diagnostics, quick fixes, and the
classpath bridge. Only the Boot version diagnostics go quiet, because those ask
Maven Central and api.spring.io — you lose the update advice rather than being
shown stale advice.
What doesn't
SpEL and query fragments inside Java strings don't get syntax colouring. That
needs LSP semantic tokens, and Zed 1.11.3 requests none for a Java buffer —
not when Spring registers the provider dynamically, and not when the official
Java server declares it statically either. Java code itself highlights fine
through Zed's own grammar, so only the colouring inside those strings is
missing. Validation and navigation ride ordinary LSP and work today.
Beyond that, Spring Initializr, the experimental embedded MCP server, and the AI
explanation commands are still waiting on a direction decision rather than more
work. The rest is written up in
known limitations.
Trying it
You'll need:
- Zed with the official Java extension (required)
- JDK 21 or newer (21.0.11 and 25.0.3 are the verified ones; 22–24 are untested)
- Rust via
rustup, which Zed requires for building a local dev extension - Network access for the first artifact download, and only that once
Clone the repo, then pick Install Dev Extension on Zed's Extensions page and
select the directory. Install the Java extension first. If JDT LS was already
running when you installed this, restart Zed so it receives the contributed
bridge bundles.
One more thing: keep at least one .java file open. Zed only starts the Java
language server for Java buffers, and no extension can start it for you. A
session with only application.properties open has no project classpath, so
property validation falls back to syntax only. The extension tells you that once
rather than reporting a failure.
CodeLens is off by default in Zed, so add "code_lens": "on" to your settings if
you want the live lenses.
Finally
Everything outside macOS arm64 is untested. If you've wanted Spring in Zed on
Linux or Windows, just running it and telling me what breaks is genuinely
useful. Issues, logs, and "why did you build it this way" questions are all
welcome.