denoland/deno
Workspace support
Active contributors: David Sherret, Bartek Iwańczuk
Purpose
A "workspace" is a deno.json (or deno.jsonc) that declares multiple member packages, each with its own config but sharing things like compiler options, lockfile, and tasks. It's the rough equivalent of npm/pnpm/yarn workspaces, sized for Deno-shaped projects.
The implementation is concentrated in libs/config, particularly libs/config/workspace/mod.rs (6,815 lines).
What a workspace looks like
A workspace root has "workspace": [...] in its deno.json:
// deno.json
{
"workspace": ["./packages/foo", "./packages/bar"],
"imports": { "@std/path": "jsr:@std/path@1" },
"tasks": { "ci": "deno test && deno lint" },
}Each member directory has its own deno.json:
// packages/foo/deno.json
{
"name": "@my-scope/foo",
"version": "0.1.0",
"exports": "./mod.ts",
}The workspace root resolves shared imports for everyone, and each member can be independently published to JSR.
What gets merged where
| Field | Behavior |
|---|---|
imports |
Member's own imports overlay the root's; root provides the defaults |
compilerOptions |
Member can override root's settings |
lint, fmt |
Member can override root's settings |
tasks |
Each member has its own; deno task from the root can run tasks across members with --recursive/--filter |
nodeModulesDir |
Set at the root; members inherit |
name, version, exports |
Per-member only — meaningful for deno publish |
| Lockfile | Single deno.lock at the root |
How resolution works
graph TD
Cwd["current dir"] --> Walk["walk up to find deno.json with 'workspace' field"]
Walk --> Root["WorkspaceRoot"]
Root --> Members["resolve each member dir"]
Members --> CurrentMember["determine which member 'cwd' is in"]
CurrentMember --> Effective["effective config = root + member overrides"]libs/config/workspace/mod.rs::WorkspaceResolver walks up from the working directory, finds the workspace root, loads each member's config, and produces a Workspace value that the rest of the CLI consumes via cli/factory.rs.
Cross-member imports
A member can import another member by its name:
// packages/foo/mod.ts
import { bar } from '@my-scope/bar';The workspace resolver maps @my-scope/bar to the file URL of packages/bar/mod.ts so type checking and runtime both work without round-tripping through JSR.
Workspace-aware subcommands
Subcommands that have workspace semantics:
| Subcommand | Workspace behavior |
|---|---|
deno task <name> |
--recursive runs the task in every member that defines it; --filter <glob> restricts |
deno publish |
Publishes every member with a name+version (in dependency order) |
deno test |
Runs tests across every member by default |
deno fmt/deno lint |
Apply across the workspace |
deno install |
Resolves npm/jsr deps for the whole workspace |
deno check |
Type-checks every member's exports plus referenced files |
Why workspace/mod.rs is so large
libs/config/workspace/mod.rs is 6,815 lines because workspace resolution has many corner cases:
- A member can also be a workspace root for a nested workspace (rare but supported).
- Symlinked members.
- Members that aren't in the directory list but get included by glob.
- Per-member
nodeModulesDiroverrides — generally disallowed but the error reporting needs to be specific. deno.jsonvsdeno.jsoncvspackage.json— a member can use any of these as its config source, with mixed-mode resolution.- Backwards compat: Deno's workspace support has evolved; old
deno.jsonshapes must keep working.
Entry points for modification
- New workspace-level config field —
libs/config/workspace/mod.rs. Plumb through tocli/factory.rsso subcommand handlers can read it. - Subcommand workspace awareness — typically each
cli/tools/<name>/accepts--recursiveand/or--filterand iteratesWorkspace::members(). - Cross-member resolution —
libs/resolver/(workspace handling is part of the unified resolver).
Key source files
| File | Purpose |
|---|---|
libs/config/lib.rs |
Crate root: deno.json parsing |
libs/config/workspace/mod.rs |
Workspace resolution (6,815 lines) |
cli/factory.rs |
Wires the resolved Workspace into per-subcommand services |
cli/tools/task.rs |
deno task workspace handling |
cli/tools/publish/ |
deno publish workspace handling |
libs/resolver/ |
Workspace-aware module resolution |
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.