Open-Source Wikis

/

Deno

/

Features

/

Workspace support

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 nodeModulesDir overrides — generally disallowed but the error reporting needs to be specific.
  • deno.json vs deno.jsonc vs package.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.json shapes must keep working.

Entry points for modification

  • New workspace-level config fieldlibs/config/workspace/mod.rs. Plumb through to cli/factory.rs so subcommand handlers can read it.
  • Subcommand workspace awareness — typically each cli/tools/<name>/ accepts --recursive and/or --filter and iterates Workspace::members().
  • Cross-member resolutionlibs/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.

Workspace support – Deno wiki | Factory