Deno 2.6: dx is the new npx
Deno 2.6 introduces the dx utility for package binary execution, enhances security with granular permissions and deno audit, accelerates type checking, and significantly improves Node.js compatibility and dependency management. This update also stabilizes key APIs and refines development workflows.
To upgrade to Deno 2.6, execute deno upgrade in your terminal. If Deno is not yet installed, follow one of the installation methods below:
- Using Shell (macOS and Linux):
curl -fsSL https://deno.land/install.sh | sh - Using PowerShell (Windows):
iwr https://deno.land/install.ps1 -useb | iex
What's New in Deno 2.6
This release introduces a host of enhancements, including:
- Running package binaries with
dx - More granular permissions
- Faster type-checking with
tsgoand LSP improvements - Wasm source phase imports
- Running CommonJS with
--require - Security auditing with
deno audit - Dependency management improvements
- Bundler enhancements
- Expanded Node.js compatibility
- API changes and stabilizations
- Significant performance boosts
- Quality-of-life improvements for developers
- V8 engine upgraded to version 14.2
Run Package Binaries with dx
Deno 2.6 unveils dx, a new utility designed as an equivalent to npx, providing a convenient way to execute binaries from npm and JSR packages.
$ dx cowsay "Hello, Deno!"
______________
< Hello, Deno! >
--------------
\
^__^
(oo)\\_______
(__)\\ )\\\/\
||----w |
|| ||
To enable dx, ensure you install its alias:
deno x --install-alias
Experienced users will note that dx operates similarly to deno run, but with key distinctions:
dxdefaults to--allow-allpermissions, unless specific permission flags are provided.dxprompts for confirmation before downloading a package.dxautomatically runs lifecycle scripts if the user accepts the download prompt.dxdefaults tonpm:<package_name>unless an alternative specifier is used.dxprevents running local files, reserving its function for package binaries.
With dx, executing package binaries becomes more intuitive, offering npx-like convenience while leveraging Deno’s robust security model and performance optimizations. Further details on dx are available in the Deno documentation.
More Granular Permissions
This release enhances control over permissions with the introduction of --ignore-read and --ignore-env flags. These allow selective suppression of file reads or environment variable access. Instead of a NotCapable error, Deno can now return NotFound for ignored file reads or undefined for ignored environment variables.
Consider this example:
main.ts
const awsSecretKey = Deno.env.get("AWS_SECRET_KEY");
console.log(awsSecretKey);
const passwd = await Deno.readTextFile("/etc/passwd");
console.log(passwd);
Running with granular ignore flags:
$ deno run --ignore-read=/etc --ignore-env=AWS_SECRET_KEY main.ts
undefined
error: Uncaught (in promise) NotFound: No such file or directory (os error 2)
at Object.readTextFile (ext:deno_fs/30_fs.js:799:24)
at file:///dev/main.ts:4:27
These flags offer greater flexibility when executing untrusted code. They address scenarios where dependencies might attempt to read numerous environment variables or configuration files, which they typically handle gracefully when missing, but previously failed on Deno's NotCapable errors. Now, such code can run without granting full permissions.
Additionally, Deno.env.toObject() now supports partial environment permissions. If only a subset of environment variables is allowed, Deno.env.toObject() will reflect this by returning only the permitted variables.
main.ts
console.log(Deno.env.toObject());
Executing with partial environment access:
$ SOME_SECRET=foo deno run --allow-env=SOME_SECRET main.ts
{ SOME_SECRET: "foo" }
An experimental permission broker is also included, offering advanced control over permission requests via a separate management process. This is particularly useful for platform authors needing to mediate permissions for untrusted code.
$ DENO_PERMISSION_BROKER_PATH=/perm_broker.sock deno run untrusted_code.ts
When active, the permission broker overrides all --allow-*, --deny-*, and --ignore-* flags, routing all permission requests to the broker process. More information is available in the Deno documentation.
Faster Type Checking with tsgo and Language Server Improvements
Deno 2.6 integrates tsgo, an experimental TypeScript type checker re-written in Go. This new checker offers significantly faster performance compared to its TypeScript-based predecessor.
Enable tsgo for deno check using the --unstable-tsgo flag or DENO_UNSTABLE_TSGO=1 environment variable:
$ deno check --unstable-tsgo main.ts
Internal projects have observed up to a 2x speed improvement in type-checking times with tsgo.
Several long-standing issues in type checking have been resolved. Deno now exhibits greater tolerance for non-standard import schemes and bare ambient module declarations, reducing false-positive errors when integrating with framework tooling or custom module loaders.
Support for common tsconfig.json options has also advanced:
compilerOptions.pathsnow functions as expected for module resolution.skipLibCheckis respected for graph errors.- Advanced settings like
isolatedDeclarationsare now supported.
These improvements contribute to a more predictable type-checking experience, especially within multi-package workspaces.
The language server (LSP) has received quality-of-life upgrades. The source.organizeImports action is now supported, enabling automatic import sorting and cleanup directly within your editor. Deno leverages the editor’s native implementation where available, ensuring a seamless experience. Test authoring is also enhanced with improved integration for describe and it style test functions, allowing editors to better understand and surface information about individual test cases.
Under-the-hood fixes make the language server less intrusive: configuration updates are detected immediately upon tsconfig.json changes, lockfiles are not written during "cache on save" operations, and lint-ignore directives behave more consistently with leading comments. These refinements minimize friction and enhance the overall developer workflow.
Wasm Source Phase Imports
Deno 2.6 introduces "source phase imports," a new JavaScript feature. Unlike standard import statements that provide a live module instance, source phase imports offer the raw source representation of a module. For WebAssembly (Wasm), this means you can import a compiled Wasm.Module directly during the build step, eliminating the need to fetch the file at runtime.
Here’s an example:
main.ts
import source addModule from "./add.wasm";
const addInstance = WebAssembly.instantiate(addModule);
const add = addInstance.exports.add;
console.log(add(1, 2));
Combined with the Wasm imports introduced in Deno v2.1, working with WebAssembly in Deno is now more ergonomic and efficient.
Run CommonJS with --require
Following the --preload flag shipped in Deno v2.4, which allows loading files before the main module executes, Deno 2.6 introduces the --require flag. This flag serves a similar purpose but is specifically designed for executing CommonJS modules instead of ES modules.
$ deno run --require ./setup.cjs main.ts
This addition further improves Deno’s Node.js compatibility by supporting a common pattern for preloading modules. Support for custom module loaders is planned for a future release.
Security Auditing with deno audit
A significant addition is the new deno audit subcommand, which helps identify security vulnerabilities in your dependencies by checking the GitHub CVE database. This command generates a report for both JSR and npm packages.
For an additional layer of security, an experimental deno audit --socket flag integrates with socket.dev:
$ deno install npm:lodahs
Add npm:lodahs@0.0.1-security
Dependencies:
+ npm:lodahs 0.0.1-security
$ deno audit --socket
No known vulnerabilities found
Socket.dev firewall report
╭ pkg:npm/lodahs@0.0.1-security
│ Supply Chain Risk: 0
│ Maintenance: 76
│ Quality: 41
│ Vulnerabilities: 100
│ License: 100
╰ Alerts (1/0/0):
[critical] malware
Found 1 alerts across 1 packages
Severity: 0 low, 0 medium, 0 high, 1 critical
The deno audit command scans your entire dependency graph against the GitHub CVE database and, if --socket is present, socket.dev’s vulnerability database. This is particularly valuable in CI/CD pipelines for enforcing build failures when vulnerabilities are detected.
If the SOCKET_API_KEY environment variable is present, Deno will use it for more detailed socket.dev reports, applying your organization’s policies and access rules.
Dependency Management
Deno 2.6 continues to refine its dependency management features, offering several notable improvements for managing, auditing, and controlling project dependencies. These enhancements address common pain points and provide better visibility into supply chain security.
Granular Control over postinstall Scripts with deno approve-scripts
Many npm packages utilize lifecycle scripts (e.g., postinstall, install, preinstall) that execute arbitrary code during installation. While often legitimate (e.g., compiling native addons, setting up configurations), these scripts also pose a security risk.
The new deno approve-scripts replaces deno install --allow-scripts, providing more ergonomic and granular control over which packages can execute these scripts.
When deno install encounters packages with unapproved lifecycle scripts, Deno will issue a warning and suggest running deno approve-scripts. This command initiates an interactive picker, allowing you to review and selectively approve or deny scripts for each package:
$ deno approve-scripts
? Select which packages to approve lifecycle scripts for (<space> to select, ↑/↓/j/k to navigate, a to select all, i to invert selection, enter to accept,
<Ctrl-c> to cancel)
○ npm:@denotest/node-addon@1.0.0
● npm:chalk@5.0.0
Your choices are saved in the allowScripts configuration within your deno.json file, creating an audit trail of packages trusted to execute code during installation.
Controlling Dependency Stability
You can now enforce a minimum age for dependencies via the deno.json configuration file, ensuring your project only uses vetted dependencies. This mitigates risks associated with newly published packages that might contain malware or breaking changes.
Specify the minimum age in your configuration:
deno.json
{
"minimumDependencyAge": "7 days"
}
This option ensures that during dependency installation or updates, only packages at least 7 days old will be used. The minimum age can be specified in minutes (e.g., "120" for two hours), ISO-8601 duration (e.g., "P2D" for two days), or RFC3339 absolute timestamp (e.g., "2025-09-16" for a cutoff date, "2025-09-16T12:00:00+00:00" for a cutoff time), or "0" to disable the feature.
Improved Lockfile and Install Workflows
The --lockfile-only flag for deno install enables updating your lockfile without downloading or installing the actual packages. This is particularly useful in CI environments for verifying dependency changes without modifying node_modules or cache, facilitating parallel builds and reducing unnecessary downloads:
$ deno install --lockfile-only # Updates deno.lock without fetching packages
$ deno install # Now installs with verified lockfile
Installation output for npm packages has been improved, offering clearer feedback on which packages were added, updated, or reused from cache, even without a traditional node_modules directory. Additionally, edge cases related to package.bin resolution and shimming on Windows have been fixed to better align with npm’s behavior, enhancing compatibility with ecosystem tools. Finally, subpath imports beginning with '#/' are now supported for improved Node.js compatibility.
Bundler Improvements
Deno 2.6 brings significant refinements to its bundler, enhancing reliability and compatibility. The bundler now works seamlessly within Web Workers, allowing dynamic code bundling in multithreaded contexts. Handling of different target platforms has improved; when bundling for the browser with --platform browser, the bundler correctly avoids Node.js-specific APIs like createRequire, ensuring clean browser-compatible bundles.
Runtime-specific specifiers such as cloudflare: and bun: are now treated as external dependencies by default, preventing them from being bundled and causing import errors:
main.ts
import { serve } from "jsr:@std/http";
import { toml } from "bun:toml"; // External, not bundled
import { parseEnv } from "cloudflare:workers"; // External, not bundled
export default {
fetch(req) {
return new Response("Hello from Cloudflare Workers");
},
};
Bundling this example:
$ deno bundle --platform browser main.ts bundle.js
# bun:toml and cloudflare:workers remain as external imports
Other improvements include fixing the transformation of import.meta.main when bundling JSR entrypoints, enhancing type safety by correctly typing the output of Deno.bundle() as Uint8Array<ArrayBuffer>, and improving development workflows so that HTML entrypoints reload properly with --watch. Reliability fixes address failed esbuild cleanup operations and internal name clashes that could lead to mysterious build failures.
Node.js Compatibility
Deno’s Node.js compatibility layer continues to mature in Deno 2.6, with dozens of improvements across file operations, cryptography, process management, and database APIs. This release underscores the commitment to making Node.js code "just work" in Deno.
@types/node Included by Default
TypeScript developers receive a major quality-of-life improvement: @types/node type declarations are now included by default. Previously, manual import of @types/node was required for proper type hints for Node.js APIs. Deno now handles this automatically, providing IDE autocompletion and type safety for all Node.js compatibility features without any setup:
import { readFile } from "node:fs/promises";
// ✅ Full type hints without manual installation
const data = await readFile("./file.txt", "utf-8");
Deno will still respect any existing @types/node version defined in your project, ensuring compatibility with specific type requirements.
Node.js API Fixes and Changes:
node:crypto- Respect
authTagLengthincreateCipherivfor GCM ciphers (#31253) - Autopadding behavior on
crypto.Cipheriv(#31389) cryptoCipherivandDecipherivbase64 encoding (#30806)- Inspect
X509Certificateclass (#30882) - Prevent cipher operations after finalize (#31533)
- Accept
ArrayBufferoncrypto.timingSafeEqual(#30773)
- Respect
node:fs- Implement
FileHandle.appendFile(data[, options])(#31301) - Implement
FileHandle.readLines()(#31107) - Missing
statfsexport fromnode:fs/promises(#31528) fs.cpandfs.cpSynccompatibility (#30502)fs.read/fs.readSyncandfs.write/fs.writeSynccompatibility (#31013)fs.readFile,fs.readFileSyncassert encoding (#30830)fs.statandfs.statSynccompatibility (#30637, #30866)fs.statfsSyncandfs.statfscompatibility (#30662)FileHandlecompatibility (#31164, #31094)fs.realpathbuffer encoding (#30885)- Respect abort signal option on
FileHandle.readFile(#31462) - Respects
flagoption onfs.readfileandfs.readfilesync(#31129) - Set default callback for
fs.close(#30720) - Validate
fs.closecallback function (#30679) - Validate
fs.readon empty buffer (#30706) - Validate
readlinkarguments (#30691) - Support option object parameter on
fs.writeandfs.writeSync(#30999) - Make
fs.globacceptURLcwd(#30705)
- Implement
node:process- Define
process.versions.sqlite(#31277) - Export
process.ppid(#31137) - False deprecation warning on
crypto.createHmac(#31025) - Implement
process:seteuid()(#31160) - Implement
process.setegid()(#31155) - Implement
process.setgid()andprocess.setuid()(#31162) process.moduleLoadListas undefined (#31022)- Ensure
process.argvis an array of strings (#31322) - Stub missing
process.sourceMapsEnabled(#31358) - Make
process.stdin.isTTYwritable (#31464) - Checking
Symbolinenvshould not ask for permission (#30965) - Handle falsy values enumerability in
process.env(#30708)
- Define
node:sqlite- Implement ‘backup’ capability (#29842)
StatementSync.iterate()should resetis_iter_finishedflag on every call (#31361)- Allow
ATTACH DATABASEwith--allow-all(#30763) - Fix
sqliteextension used for testing; ensure related tests are actually meaningful (#31455) - Implement
DatabaseSync.aggregate()(#31461) - Implement
DatabaseSync.function()and better error details (#31386) - Implement
StatementSync#columns()method (#31119) setAllowUnknownNamedParameterserror message (#31319)sqlite.DatabaseSyncexplicit resource management compatibility (#31311)- Fix segfault on calling
StatementSyncmethods after connection has closed (#31331) - Add
setAllowUnknownNamedParametersoption (#31202)
- Other Assorted Changes:
- Fix misused
napi_callback_infoinCallbackInfo(#30983) - Ensure that the
node:consoleimplementation has an implementation foremitWarningin scope (#31263) - Support advanced serialization in IPC (#31380)
deepStrictEqualnow correctly handlesNumberobjects (#31233)- Return string
familyinserver.address()(#31465) - Ensure active timers entry is deleted on
Timeout.prototype.refresh(#31436) dns.resolve6compatibility (#30974)path.matchesGlobcompatibility (#30976)url.domainToASCIIreturns empty string for invalid domains (#31219)- Avoid stack overflow in
node:zlib’sgunzip(#30865) cpus()should not error when there’s no cpu info (#31097)- Ensure
'exit'event is fired only once forworker_threads(#31231) - Handle empty writes in chunked HTTP requests (#31066)
- Handle multiple calls in
inspector.Session.post()(#31067) - Implement
dns.lookupService(#31310) - Implement
fchmodon Windows (#30704) - Implement
performance.timerify()(#31238) - Implement
util.getSystemErrorMessage()(#31147) - Inconsistent error message thrown by
AssertionError(#31089) - Make
kReinitializeHandlework for TLS wrap (#31079) - Map
BadResourceerror to the corresponding Node error (#30926) - Omit
smifromzlib.crc32op function (#30907) - Reimplement
setImmediateAPI (#30328) setTimeoutpromisified to handle abort signal (#30855)- Truncate first non-hex value on
Buffer.from(#31227)
- Fix misused
API Changes
Deno 2.6 introduces new APIs and stabilizes existing ones.
-
The
BroadcastChannelAPI is now stable, simplifying communication across workers and contexts.main.tsconst channel = new BroadcastChannel("my-channel"); channel.onmessage = (event) => { console.log("Message from worker:", event.data); }; const worker = new Worker("./worker.ts"); worker.postMessage("Hello from main");worker.tsconst channel = new BroadcastChannel("my-channel"); channel.postMessage("Hello from worker"); -
Web streams (
ReadableStream,WritableStream, andTransformStream) now support transferability, allowing efficient passing between workers without copying.transfer.tsconst INDEX_HTML = Deno.readTextFileSync("./index.html"); const worker = new Worker("./the_algorithm.js", { type: "module" }); Deno.serve(async (req) => { if (req.method === "POST" && req.path === "/the-algorithm") { const { port1, port2 } = new MessageChannel(); worker.postMessage( { stream: req.body, port: port1 }, { transfer: [req.body, port1] }, ); const res = await new Promise((resolve) => { port1.onmessage = (e) => resolve(e.data); }); return new Response(res); } if (req.path === "/") { return new Response(INDEX_HTML, { "content-type": "text/html" }); } return new Response(null, { status: 404 }); }); -
ImageDatanow supportsFloat16Array, offering more efficient memory usage for certain image processing workflows.image_data.tsconst imageData = new ImageData( new Float16Array(width * height * 4), width, height, ); -
Signal handling is improved with support for integer signals in
Deno.kill()and child process kill methods. -
Deno.HttpClientnow works withWebSocketconnections, including new TCP proxy support.main.tsconst client = new Deno.HttpClient({ allowHost: true, proxy: { url: new URL("http://proxy.example.com:8080") }, }); const ws = new WebSocket("wss://api.example.com/socket", { httpClient: client, });
Performance Improvements
Deno 2.6 delivers performance enhancements across the platform.
- A memory leak in the
fetchAPI, which affected multi-threaded programs, has been resolved. - V8 engine integration is optimized with stack-allocated scopes, reducing memory allocation overhead and improving garbage collection efficiency.
package.jsonresolution now employs negative caching, preventing repetitive checks for non-existent files and yielding significant performance boosts for projects with numerous dependencies.- For Node.js compatibility, critical operations like
getOwnNonIndexPropertiesandBuffer.comparehave been moved to native code, improving performance for code relying on these APIs.
Quality of Life Improvements
Beyond major features, Deno 2.6 introduces numerous smaller yet impactful improvements for a smoother development experience.
-
The
deno install -gcommand now requires a--separator when passing arguments to installed scripts, preventing ambiguity betweendenoflags and script-specific flags. Additionally, multiple global packages can now be installed in a single command:# Install multiple packages at once deno install -g npm:prettier npm:typescript -
For JSR package publishers, adding
"publish": falsetodeno.jsonprevents accidental publishing of monorepo packages or private modules.deno.json{ "name": "@myorg/private-tools", "publish": false } -
Test coverage improvements enhance code quality measurement. Coverage data is now collected from workers (previously excluded), and Blob URLs are properly excluded to reduce noise from dynamically generated code. HTML coverage reports now include a dark mode toggle for improved readability. JUnit test reports are now correctly formatted without ANSI escape codes, ensuring compatibility with CI/CD systems expecting clean XML.
-
Stack traces have been dramatically improved with better filtering of internal frames. Deno now filters out noisy internal frames, dims internal Deno runtime frames in grey for clearer distinction from user code, and shows relative paths for enhanced readability:
Error formatting in Deno v2.5
Error formatting in Deno v2.6 -
Command-line completions for
deno taskare now dynamic and context-aware. As tasks are defined indeno.json, shell autocompletion will automatically discover and suggest them. Remember to re-generate shell completions after upgrading usingdeno completions --dynamic. -
The lint plugin API now has access to
envandreadpermissions, enabling more sophisticated linting rules that can interact with environment configuration and read files. -
A small but useful feature is the
--emptyflag fordeno init, which creates an emptydeno.jsonfile, ideal for starting new projects from scratch.$ deno init --empty ✅ Project initialized $ cat deno.json {} -
Source map support has been improved with native runtime support. When an exception is thrown, Deno will now check for "magic" comments like
//# sourceMappingURL=...and apply the source map to the stack trace, enhancing debugging.
V8 14.2
Deno 2.6 upgrades the V8 engine to version 14.2, incorporating the latest performance improvements, bug fixes, and new JavaScript features from the V8 team.