Deno 2.8 dropped yesterday, and it’s not a minor release in any meaningful sense. Six new CLI subcommands, a 3.66x faster package manager, built-in CPU profiling with flamegraphs, Chrome DevTools network inspection, and a Node.js compatibility pass rate that jumped from 42% to 76.4%. If you wrote Deno off as “that other runtime,” it might be time to look again.
The Six New Subcommands
The headline feature is that Deno’s CLI now covers the full lifecycle of a JavaScript/TypeScript project — from dependency management through versioning, security auditing, and packaging. Here’s what’s new:
deno audit fix — Automated Vulnerability Patching
deno audit (added in 2.6) reports known vulnerabilities in your npm dependency tree. The new deno audit fix goes further: it automatically upgrades affected packages to the nearest patched version that still satisfies your version constraints. Anything requiring a major-version bump is listed separately so you can decide whether to relax the constraint.
$ deno audit fix
╭ body-parser vulnerable to denial of service
│ Severity: high
│ Package: body-parser
│ Vulnerable: <1.20.3
╰ Info: https://github.com/advisories/GHSA-qwcr-r2fm-qrc7
Fixed 1 vulnerability:
body-parser 1.19.0 -> 1.20.3
1 vulnerability could not be fixed automatically:
express (major upgrade to 5.0.0)
The same behavior is available as deno audit --fix if you prefer the flag form. Drop it into a CI workflow and you get automated patch-level security fixes without touching a config file.
deno bump-version — Semver With Conventional Commits
Version bumping sounds trivial until you manage a monorepo with cross-package references. deno bump-version handles the simple case (bump patch, minor, major, prerelease) and the complex one: in a workspace, it applies the same increment to every member package and rewrites jsr: version constraints in the root config and import map so cross-package references stay in sync.
# Simple bump
$ deno bump-version patch # 1.4.6 -> 1.4.7
# Workspace-aware: bumps every member
$ deno bump-version patch
# Derive per-package bumps from Conventional Commits
$ deno bump-version --base=main --dry-run
The --dry-run flag prints planned changes without writing anything. Without an increment argument in workspace mode, it derives per-package bumps from Conventional Commits between a base ref and the current branch — honoring scoped commits, BREAKING footers, and 0.x.y semver semantics.
deno ci — Reproducible Installs Without the Flags
CI scripts want one thing: “give me exactly what the lockfile says, and fail loudly if anything is off.” deno ci wraps that intent in a single command. It errors if deno.lock is missing, removes any existing node_modules, and runs the install with --frozen so the lockfile must match the config exactly.
$ deno ci # errors without lockfile, enforces frozen install
$ deno ci --prod # skip devDependencies and @types/*
The --prod flag (also new in 2.8 on deno install) skips devDependencies and @types/* packages — useful for Docker builds where install size matters.
deno pack — Build npm-Publishable Tarballs in One Shot
deno pack is closer to tsc + npm pack combined than to npm pack alone. Given a deno.json with a name, version, and exports field, it produces a deterministic tarball containing transpiled JavaScript, .d.ts declaration files, and a generated package.json with the right conditional exports. Specifier rewriting happens automatically: jsr:@std/path becomes @jsr/std__path, npm:express@4 becomes express, and relative .ts imports become .js.
$ deno pack # build the tarball
$ deno pack --dry-run # preview the file list
$ deno pack --set-version 2.0.0 # override version
$ deno pack --output my-package.tgz # custom output path
File selection is graph-based — only modules reachable from your declared exports are bundled, not everything in the directory. This is the right default: your published package contains exactly what your public API touches.
deno transpile — Just the Emit Step
Sometimes you don’t need a bundler, a module rewriter, or a build pipeline. You just need TypeScript stripped down to JavaScript. deno transpile does exactly that — no bundling, no module rewriting, no config.
$ deno transpile greeter.ts -o greeter.js
$ deno transpile src/ --outdir dist/ --declaration --source-map separate
It accepts multiple files, --outdir for batch output, --source-map for source maps, and --declaration to emit .d.ts alongside the JavaScript. Useful for publishing JS-only artifacts or pre-building TypeScript for runtimes that don’t handle it natively.
deno why — Trace Any Dependency
Equivalent to npm explain / pnpm why, deno why <package> walks from your direct dependencies down to the package in question, listing each path through the tree. It works with both npm and JSR dependencies.
$ deno why qs
qs@6.14.2
npm:express@4 > qs@6.14.2
qs@6.15.1
npm:express@4 > body-parser@1.20.5 > qs@6.15.1
Performance and Node Compatibility
The new subcommands are the visible changes, but the invisible ones matter just as much for daily workflow. Cold npm installs are 3.66x faster (3,319ms down to 906ms on a fresh cache), thanks to abbreviated packuments, parallel resolution, and off-loop decompression. Node HTTP throughput more than doubled (2.21x), and base64 operations are 3.07x faster via simdutf.
Node.js API compatibility jumped from ~42% to 76.4% against Node’s own test suite — 500 commits touching nearly every node: module. Many Node built-in modules are now lazy-loaded, so programs that don’t touch them start faster. Deno now defaults to npm for unprefixed package names at the CLI, so deno add express works the same way npm install express does.
Built-In Profiling and Debugging
Two features that previously required external tooling are now built into the runtime:
- CPU profiling with flamegraphs: Run
deno run --cpu-prof --cpu-prof-flamegraph main.tsand get a self-contained, interactive SVG flamegraph you can open in any browser. Add--cpu-prof-mdfor a terminal-friendly Markdown report showing the hottest functions and call tree. No external profiler needed. - Chrome DevTools network inspection: Run with
--inspect-wait, openchrome://inspectin Chromium, and the DevTools Network tab now shows everyfetch(),node:httprequest, and WebSocket — with headers, status codes, bodies, and timing.
import defer — Lazy Module Evaluation
Deno 2.8 implements the TC39 import defer proposal: a module is loaded and parsed without running its top-level code, then evaluated only on first access to its exports. This is useful for trimming startup time when a module is expensive but rarely used on a given code path.
import defer * as heavy from "./heavy-module.ts";
// heavy-module.ts is parsed but NOT evaluated yet
console.log("module loaded");
// NOW it evaluates — only when we actually need it
const result = heavy.processData(data);
The same semantics work with import.defer() for dynamic imports — pre-load both branches of a decision, but only evaluate the one you pick. Works in .ts and .tsx files with no extra setup.
Monorepo Support: The catalog: Protocol
Monorepos that share dependency versions across packages no longer need manual coordination. Deno 2.8 adopts pnpm’s catalog: protocol — declare versions once in the workspace root and reference them by name from each member.
// deno.json (workspace root)
{
"workspace": ["./packages/api", "./packages/web"],
"catalog": {
"hono": "^4.6.0",
"zod": "^3.23.0"
}
}
// packages/api/package.json
{
"dependencies": {
"hono": "catalog:",
"zod": "catalog:"
}
}
Named catalogs (catalog:runtime, catalog:tools) let you separate production dependencies from build tooling. Bump a version once in the root, and every member picks it up.
The Bigger Picture
Deno 2.8 is the clearest signal yet that the Deno team isn’t building “an alternative to Node” — they’re building a complete developer platform. The CLI now covers dependency management (add, install, remove, ci, why), security (audit, audit fix), versioning (bump-version), packaging (pack), transpilation, compilation (compile with framework auto-detection), and profiling — all without leaving the deno binary.
The npm: prefix is no longer required at the CLI. Node types are included by default. The catalog protocol and workspace-aware versioning handle monorepo coordination. And with TypeScript 6.0.3 bundled and lib.node included in every type-check, the migration path from a Node project is getting shorter.
If you haven’t tried Deno recently, the official docs are the best place to start. The deno compile workflow (now with framework auto-detection for Next.js, Astro, Fresh, SvelteKit, and others) alone is worth the upgrade for anyone shipping single-binary deployments.
Upgrade with deno upgrade or install fresh:
# macOS / Linux
curl -fsSL https://deno.land/install.sh | sh
# Windows (PowerShell)
irm https://deno.land/install.ps1 -useb | iex