Node compatibility mode
Starting with v1.15 Deno provides Node compatibility mode that makes it possible
to run a subset of programs authored for Node directly in Deno. Compatibility
mode can be activated by passing --compat
flag in CLI.
⚠️ Using compatibility mode currently requires the
--unstable
flag. If you intend to use CJS modules, the--allow-read
flag is needed as well.
⚠️ Package management is currently out of scope for Node compatibility mode. For the time being we suggest to keep using your current solution (
npm
,yarn
,pnpm
).
Example
eslint
is a very popular tool used by most of Node
projects. Let’s run eslint
using Deno in Node compatibility mode. Assuming
that eslint
is already installed locally (either using npm install eslint
or
yarn install eslint
) we can do so like:
$ ls
.eslintrc.json
node_modules
package.json
test.js
test.ts
$ cat test.js
function foo() {}
$ cat test.ts
function bar(): any {}
$ deno run \
--compat --unstable \
--allow-read --allow-write=./ --allow-env \
node_modules/eslint/bin/eslint.js test.js test.ts
/dev/test.js
1:10 warning 'foo' is defined but never used @typescript-eslint/no-unused-vars
1:16 error Unexpected empty function 'foo' @typescript-eslint/no-empty-function
/dev/test.ts
1:10 warning 'bar' is defined but never used @typescript-eslint/no-unused-vars
1:17 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any
1:21 error Unexpected empty function 'bar' @typescript-eslint/no-empty-function
✖ 5 problems (2 errors, 3 warnings)
⚠️ Notice that ESLint is run with limited set of permissions. We only give it access to the read from the file system, write to current directory and access environmental variables. Programs run in compatility mode are subject to Deno’s permission model.
How does it work?
When using compatibility mode there Deno does a few things behind the scenes:
Node globals are set up and made available in the global scope. That means that APIs like
process
,global
,Buffer
,setImmediate
orclearImmediate
are available just like in Node. This is done by executingstd/node/global.ts
on startup.Node built-in modules are set up and made available to import statements and
require()
calls. Following calls will return appropriate Node modules polyfilled usingstd/node
:import fs from "fs";
import os from "node:os";
const path = require("path");
const http = require("node:http");
Deno will support Node resolution algorithm so importing packages using “bare” specifiers will work. For details on how module resolution works check Node documentation on CJS and ES modules.
Module resolution
CommonJS resolution is implemented as in Node and there should be no observable differences.
ES module resolution is implemented on top of Deno’s regular ESM resolution, leading to a few additional properties compared to Node:
In addition to
file:
anddata:
URL schemes supported in Node;http:
,https:
andblob:
URL schemes will work in the same way if you used Deno without compatibility mode.Import maps are supported in the same way if you used Deno without compatibility mode. When resolving “bare” specifiers Deno will first try to resolve them using import map (if one is provided using
--import-map
flag). Bare specifiers starting withnode:
prefix are extempt from this rule.Deno respects “Conditional exports” field in
package.json
; in addition to conditions recognized by Node,"deno"
condition can be used. This property is useful to the package authors who want to provide separate entrypoint optimized for use with Deno. As an example, imagine that your package usesnode-fetch
. By providing a conditional"deno"
export, you can add an entrypoint that doesn’t depend onnode-fetch
and instead uses built-infetch
API in Deno.
Node built-in modules
Following built-in Node modules are currently supported:
assert
(partly)assert/strict
(partly)buffer
console
(partly)constants
crypto
(partly)child_process
(partly)dns
(partly)events
fs
(partly)fs/promises
(partly)http
(partly)module
net
(partly)os
(partly)path
perf_hooks
(partly)process
(partly)querystring
readline
(partly)stream
string_decoder
sys
(partly)timers
timers/promises
tty
(partly)url
(partly)util
(partly)worker_threads
(partly)
Following modules are not yet implemented:
cluster
dgram
http2
https
repl
tls
vm
zlib
If you try to run Node code that requires any of the not implemented modules, please open an issue in https://github.com/denoland/deno_std/issues with example code.
TypeScript support
Currently, the compatibility mode does not support TypeScript.
In the upcoming releases we plan to add support for a types
field in
package.json
, to automatically lookup types and use them during type checking.
In the long term, we’d like to provide ability to consume TypeScript code authored for the Node runtime.