Deno 2.0 Workspaces: Build Monorepos with JSR Packages and TypeScript-First Development
Deno 2.0 Workspaces: Implementing JSR Packages and Monorepo-First Development
Deno 2.0 introduces native workspace support and seamless JSR integration, enabling efficient monorepo management with TypeScript-first package development.
Workspace Configuration
Configure your monorepo root with deno.json:
{
"workspace": ["./packages/*", "./tools/*"],
"fmt": {
"useTabs": true,
"lineWidth": 80
},
"lint": {
"rules": {
"tags": ["recommended"]
}
}
}
Member Package Structure
Each workspace member requires its own deno.json:
// packages/my-package/deno.json
{
"name": "@scope/my-package",
"version": "0.1.0",
"exports": "./mod.ts",
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"strict": true,
"declaration": true
}
}
JSR Package Integration
Define package metadata in your member's deno.json:
{
"name": "@scope/utils",
"version": "1.0.0",
"exports": {
".": "./mod.ts",
"./helpers": "./helpers.ts"
},
"imports": {
"@std/testing": "jsr:@std/testing@^1.0.0"
}
}
TypeScript Configuration
Deno 2.0 consolidates TypeScript configuration in deno.json. JSR packages publish source files directly, so no output directory is needed:
// packages/my-package/deno.json
{
"name": "@scope/my-package",
"version": "0.1.0",
"exports": "./mod.ts",
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"declaration": true
}
}
Monorepo Development Workflow
Install dependencies across all workspaces:
deno install
Run tasks across all packages from the workspace root:
deno task test
deno task build
deno task lint
To run a task in a specific package:
deno task --cwd=packages/my-package build
Local Development
Add dependencies to a specific package:
cd packages/my-package
deno add @std/assert
For cross-package imports within the workspace, use the bare specifier defined in the member's name field:
// packages/app/mod.ts
import { helper } from "@scope/utils";
For external JSR packages, use the jsr: specifier:
import { assertEquals } from "jsr:@std/assert@^1.0.0";
Publishing to JSR
Publish individual packages:
cd packages/my-package
deno publish
Automated Publishing
Configure CI/CD with OIDC authentication for JSR:
# .github/workflows/publish.yml
name: Publish to JSR
on:
push:
tags: ["packages/*/v*"]
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
strategy:
matrix:
package: [packages/my-package, packages/utils]
steps:
- uses: actions/checkout@v4
- uses: denoland/setup-deno@v1
with:
deno-version: v2.x
- run: deno publish
working-directory: ${{ matrix.package }}
The id-token: write permission enables OIDC authentication with JSR. Alternatively, you can use a JSR_API_KEY secret:
- run: deno publish
env:
JSR_API_KEY: ${{ secrets.JSR_API_KEY }}
Dependency Management
Use workspace-scoped imports:
// deno.json (root)
{
"workspace": ["./packages/*"],
"imports": {
"@std/testing": "jsr:@std/testing@^1.0.0",
"@std/assert": "jsr:@std/assert@^1.0.0"
}
}
Cross-Package Dependencies
Reference workspace members using bare specifiers based on the name field:
// packages/app/mod.ts
import { helper } from "@scope/utils";
Testing Strategy
Run tests across all packages from the workspace root:
deno test
Run tests for a specific package:
deno test packages/my-package/
Or change to the package directory:
cd packages/my-package
deno test
Best Practices
- Version Management: Use semantic versioning for all packages
- Dependency Isolation: Each package manages its own dependencies
- Build Optimization: Cache dependencies globally with
deno install - Documentation: Leverage JSR's auto-generated docs from JSDoc
Common Commands
# Initialize new workspace member
mkdir packages/new-package
cd packages/new-package
deno init
# Add dependency to specific package
cd packages/my-package
deno add @std/assert
# Format all packages (runs from root)
deno fmt
# Lint all packages (runs from root)
deno lint
# Run tests across all packages
deno test
Deno 2.0 workspaces provide a streamlined approach to monorepo management with native JSR integration, eliminating complex tooling while maintaining TypeScript-first development practices.
Share this Guide:
More Guides
Agentic Workflows: Building Self-Correcting Loops with LangGraph and CrewAI State Machines
Build production-ready AI agents that iteratively improve their outputs through automated feedback loops, combining LangGraph's state machine architecture with CrewAI's multi-agent orchestration for robust, self-correcting workflows.
14 min readBun Runtime Migration: Porting High-Traffic Node.js APIs with Native APIs and SQLite
Learn how to migrate high-traffic Node.js APIs to Bun for 4× HTTP throughput and 3.8× database performance gains using native APIs and bun:sqlite.
10 min readGleam on BEAM: Building Type-Safe, Fault-Tolerant Distributed Systems
Learn how Gleam combines Hindley-Milner type inference with Erlang's actor-based concurrency model to build systems that are both compile-time safe and runtime fault-tolerant. Covers OTP integration, supervision trees, and seamless interoperability with the BEAM ecosystem.
5 min readHono Edge Framework: Build Ultra-Fast APIs for Cloudflare Workers and Bun
Master Hono's zero-dependency web framework to build low-latency edge APIs that deploy seamlessly across Cloudflare Workers, Bun, and other JavaScript runtimes. Learn routing, middleware, validation, and real-time streaming patterns optimized for edge computing.
6 min readLLM Observability: OpenTelemetry Tracing for Non-Deterministic AI Chains
Master OpenTelemetry tracing for LLM workflows with semantic conventions, token metrics, and non-deterministic chain monitoring for production AI systems.
9 min readContinue Reading
Agentic Workflows: Building Self-Correcting Loops with LangGraph and CrewAI State Machines
Build production-ready AI agents that iteratively improve their outputs through automated feedback loops, combining LangGraph's state machine architecture with CrewAI's multi-agent orchestration for robust, self-correcting workflows.
14 min readBun Runtime Migration: Porting High-Traffic Node.js APIs with Native APIs and SQLite
Learn how to migrate high-traffic Node.js APIs to Bun for 4× HTTP throughput and 3.8× database performance gains using native APIs and bun:sqlite.
10 min readGleam on BEAM: Building Type-Safe, Fault-Tolerant Distributed Systems
Learn how Gleam combines Hindley-Milner type inference with Erlang's actor-based concurrency model to build systems that are both compile-time safe and runtime fault-tolerant. Covers OTP integration, supervision trees, and seamless interoperability with the BEAM ecosystem.
5 min readReady to Supercharge Your Development Workflow?
Join thousands of engineering teams using MatterAI to accelerate code reviews, catch bugs earlier, and ship faster.
