On this page
- Migrating from Node.js to Deno
- Node specifiers
- Node to Deno Cheatsheet
- Built-in Node.js globals
- Node Compatibility
- Built-in module support
- node:assert
- node:async_hooks
- node:buffer
- node:child_process
- node:cluster
- node:console
- node:crypto
- node:dgram
- node:diagnostics_channel
- node:dns
- node:domain
- node:events
- node:fs
- node:http
- node:http2
- node:https
- node:inspector
- node:module
- node:net
- node:os
- node:path
- node:perf_hooks
- node:punycode
- node:process
- node:querystring
- node:readline
- node:repl
- node:stream
- node:string_decoder
- node:sys
- node:test
- node:timers
- node:tls
- node:trace_events
- node:tty
- node:util
- node:url
- node:v8
- node:vm
- node:wasi
- node:worker_threads
- node:zlib
- Globals
- Unstable compatibility features
Node compatibility and interop
Modern Node.js projects will run in Deno with little to no reworking required. However, there are some key differences between the two runtimes that you can take advantage of to make your code simpler and smaller when migrating your Node.js projects to Deno.
Migrating from Node.js to Deno Jump to heading
Running your Node.js project with Deno is a straightforward process, the main points to be aware of are:
- Usage of Node.js globals (like
process
,Buffer
, etc) - Imported Node.js built-in modules need the
node:
specifier (fs
->node:fs
)
If your project is written with CommonJS (i.e. require
), you will need to
update it to use ECMAScript modules, check out our helpful
CommonJS to ESM guide to get you up and
running with Deno.
Node.js built-ins Jump to heading
In Node.js 20 and earlier, built-in modules in the Node.js standard library
could be imported with "bare specifiers". Consider the Node program below with a
.mjs
extension:
import * as os from "os";
console.log(os.cpus());
The os
module is built in to the
Node.js runtime, and can be imported using a bare specifier as above.
The .mjs
file extension is supported but not required in Deno. Because Node
doesn't support ESM by default, it requires you to name any files that use ESM
with a .mjs
file extension.
Node specifiers Jump to heading
Deno provides a compatibility layer that allows the use of Node.js built-in APIs
within Deno programs. However, in order to use them, you will need to add the
node:
specifier to any import statements that use them.
For example - if you update the code above to be this instead:
import * as os from "node:os";
console.log(os.cpus());
And run it with deno run index.mjs
- you will notice you get the same output
as running the program in Node.js. Updating any imports in your application to
use node:
specifiers should enable any code using Node built-ins to function
as it did in Node.js.
Runtime permissions in Deno Jump to heading
Consider the following simple Express server:
import express from "npm:express@4";
const app = express();
app.get("/", function (_req, res) {
res.send("hello");
});
app.listen(3000, () => {
console.log("Express listening on :3000");
});
If you run the above with deno run server.js
, you will be prompted for
permissions required to execute the code and its dependencies. For example:
$ deno run server.js
┌ ⚠️ Deno requests net access to "0.0.0.0:8000".
├ Requested by `Deno.listen()` API.
├ Run again with --allow-net to bypass this prompt.
└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all net permissions) >
Deno features runtime security by default, meaning that you as the developer must opt in to giving your code access to the filesystem, network, system environment, and more. Doing this prevents supply chain attacks and other potential vulnerabilities in your code. By comparison, Node.js has no concept of runtime security, with all code executed with the same level of permission as the user running the code.
To run your code as you would in Node.js, you can pass the -A
flag to enable
all permissions.
deno run -A server.js
For more granular control, you can enable access to specific features by opting in to individual permissions.
Running scripts from package.json Jump to heading
Deno supports running npm scripts natively with the
deno task
subcommand. Consider the following
Node.js project with a script called start
inside its package.json
:
{
"name": "my-project",
"scripts": {
"start": "eslint"
}
}
You can execute this script with Deno by running:
deno task start
Node.js global objects Jump to heading
In Node.js, there are a number of
global objects available in the scope of
all programs, like the process
object, Buffer
, or __dirname
and
__filename
.
Deno does not add additional objects and variables to the global scope, other
than the Deno
global. Any API that doesn't exist
as a web-standard browser API will be found in Deno
. Alternatively, you can
import Node.js built-in modules using the node:
specifier.
import process from "node:process";
import { Buffer } from "node:buffer";
const __filename = import.meta.filename;
const __dirname = import.meta.dirname;
If you do run into a problem with Node.js compatibility, please let us know by opening an issue on GitHub.
Optional improvements with Deno's built-in tools Jump to heading
One of Deno's core strengths is a unified toolchain that comes with support for TypeScript out of the box, and tools like a linter, formatter and a test runner. Switching to Deno allows you to simplify your toolchain and reduces the number of moving components in your project. Deno also has a more secure runtime, with runtime permissions that allow you to control what your code can access.
deno.json (optional) Jump to heading
Deno has its own config file, deno.json
or deno.jsonc
, which can be used to
configure your project. You can use it to define tasks, dependencies, path
mappings, and other runtime configurations.
Migrating npm scripts to deno.json (optional) Jump to heading
If preferred, you can move your npm scripts over to deno.json
, where they can
be run using deno task
. This allows you to manage all necessary permission
flags and other runtime configuration in one place.
{
"tasks": {
"dev": "deno run --allow-net --allow-read --allow-env server.js"
}
}
deno task dev
Migrating npm dependencies to deno.json (optional) Jump to heading
You can also migrate your dependencies over to deno.json
. Deno supports
importing dependencies from external package repositories, local files, and/or
URLs. To import your npm dependencies, you can add them to the imports
field
in deno.json
, and add the npm:
specifier to the import path:
{
"imports": {
"express": "npm:express@4"
}
}
Deno supports multiple package registries and allows you to import dependencies from npm, JSR and HTTP URLs.
{
"imports": {
"express": "npm:express@4",
"@luca/cases": "jsr:@luca/cases@1",
"foo": "https://example.com/foo.ts"
}
}
Linting (optional) Jump to heading
Deno ships with a built-in linter that is written with performance in mind. Deno can lint large projects in just a few milliseconds. You can try it out on your project by running:
deno lint
This will lint all files in your project. When the linter detects a problem, it will show the line in your editor and in the terminal output. An example of what that might look like:
error[no-constant-condition]: Use of a constant expressions as conditions is not allowed.
--> /my-project/bar.ts:1:5
|
1 | if (true) {
| ^^^^
= hint: Remove the constant expression
docs: https://lint.deno.land/rules/no-constant-condition
Found 1 problem
Checked 4 files
Many linting issues can be fixed automatically by passing the --fix
flag:
deno lint --fix
A full list of all supported linting rules can be found on
https://lint.deno.land/. To learn more about how to
configure the linter, check out the deno lint
subcommand.
Formatting (optional) Jump to heading
Deno ships with a built-in formatter that can optionally format your code according to the Deno style guide. You can run the formatter on your project by running:
deno fmt
If using deno fmt
in CI, you can pass the --check
argument to make the
formatter exit with an error when it detects improperly formatted code.
deno fmt --check
The formatting rules can be configured in your deno.json
file. To learn more
about how to configure the formatter, check out the
deno fmt
subcommand.
Testing (optional) Jump to heading
Deno encourages writing tests for your code, and provides a built-in test runner to make it easy to write and run tests. The test runner is tightly integrated into Deno, so that you don't have to do any additional configuration to make TypeScript or other features work.
Deno.test("my test", () => {
// Your test code here
});
deno test
When passing the --watch
flag, the test runner will automatically reload when
any of the imported modules change.
To learn more about the test runner and how to configure it, check out the
deno test
subcommand documentation.
Node to Deno Cheatsheet Jump to heading
Node.js | Deno |
---|---|
node file.js |
deno run file.js |
ts-node file.ts |
deno run file.ts |
nodemon |
deno run --watch |
node -e |
deno eval |
npm i / npm install |
deno install |
npm install -g |
deno install -g |
npm run |
deno task |
eslint |
deno lint |
prettier |
deno fmt |
package.json |
deno.json or package.json |
tsc |
deno check ¹ |
typedoc |
deno doc |
jest / ava / mocha / tap / etc |
deno test |
nexe / pkg |
deno compile |
npm explain |
deno info |
nvm / n / fnm |
deno upgrade |
tsserver |
deno lsp |
nyc / c8 / istanbul |
deno coverage |
benchmarks | deno bench |
¹ Type checking happens automatically, TypeScript compiler is built into the
deno
binary.
Built-in Node.js globals Jump to heading
Deno provides a similar set of built-in globals as Node.js, but with some differences. Here are some common ones:
Node.js | Deno |
---|---|
process.cwd() |
Deno.cwd() |
process.env.MY_ENV |
Deno.env.get("MY_ENV") |
process.env.MY_ENV = "foo" |
Deno.env.set("MY_ENV", "foo") |
process.platform |
Deno.build.os |
process.arch |
Deno.build.arch |
process.execPath() |
Deno.execPath() |
process.exit(code) |
Deno.exit(code) |
It is also possible to import Node.js modules into your project using the
node:
specifier. For example:
import process from "node:process";
APIs Jump to heading
Node.js | Deno |
---|---|
fsPromises.readFile(filePath, "utf-8") |
Deno.readTextFile(filePath) |
Node Compatibility Jump to heading
Deno provides polyfills for a number of built-in Node.js modules and globals. For a full list of Node built-in modules, see the reference.
Node compatibility is an ongoing project - help us identify gaps and let us know which modules you need by opening an issue on GitHub.
Built-in module support Jump to heading
node:async_hooks
Jump to heading
AsyncLocalStorage
is supported. AsyncResource
, executionAsyncId
, and
createHook
are non-functional stubs.
node:cluster
Jump to heading
All exports are non-functional stubs.
node:crypto
Jump to heading
Missing Certificate
class, crypto.Cipheriv.prototype.setAutoPadding
,
crypto.Decipheriv.prototype.setAutoPadding
, crypto.publicDecrypt
,
crypto.ECDH.prototype.convertKey
, x448
option for generateKeyPair
,
crypto.KeyObject
, safe
, add
and rem
options for generatePrime
,
crypto.Sign.prototype.sign
and crypto.Verify.prototype.verify
with non
BinaryLike
input, crypto.secureHeapUsed
, crypto.setEngine
, legacy methods
of crypto.X509Certificate
.
node:dgram
Jump to heading
Some dgram.Socket
instance methods are non-functional stubs:
addMembership
addSourceSpecificMembership
dropMembership
dropSourceSpecificMembership
setBroadcast
setMulticastInterface
setMulticastLoopback
setMulticastTtl
setTtl
node:dns
Jump to heading
Missing dns.resolve*
with ttl
option.
node:domain
Jump to heading
All exports are non-functional stubs. This is a deprecated Node module.
node:fs
Jump to heading
node:fs
Missing utf16le
, latin1
and ucs2
encoding for fs.writeFile
and
fs.writeFileSync
.
node:fs/promises
Missing lchmod
.
node:http
Jump to heading
createConnection
option is currently not supported.
node:http2
Jump to heading
Partially supported, major work in progress to enable grpc-js
.
node:https
Jump to heading
Missing https.Server.opts.cert
and https.Server.opts.key
array type.
node:inspector
Jump to heading
console
is supported. Other APIs are stubs and will throw an error.
node:module
Jump to heading
The register()
function is not supported.
node:net
Jump to heading
Missing net.Socket.prototype.constructor
with fd
option.
node:perf_hooks
Jump to heading
Missing perf_hooks.eventLoopUtilization
, perf_hooks.timerify
,
perf_hooks.monitorEventLoopDelay
.
node:process
Jump to heading
Missing multipleResolves
, worker
events.
node:repl
Jump to heading
builtinModules
and _builtinLibs
are supported. Missing
REPLServer.prototype.constructor
and start()
.
node:test
Jump to heading
Currently only test
API is supported.
node:tls
Jump to heading
Missing createSecurePair
.
node:trace_events
Jump to heading
All exports are non-functional stubs.
node:util
Jump to heading
Missing aborted
, transferableAbortSignal
, transferableAbortController
,
MIMEParams
, MIMEType
and getSystemErrorMap
.
node:v8
Jump to heading
cachedDataVersionTag
and getHeapStatistics
are supported.
setFlagsFromStrings
is a noop. Other APIs are not supported and will throw an
error.
node:vm
Jump to heading
Partial support.
node:wasi
Jump to heading
All exports are non-functional stubs.
node:worker_threads
Jump to heading
Missing parentPort.emit
, parentPort.removeAllListeners
,
markAsUntransferable
, moveMessagePortToContext
, receiveMessageOnPort
,
Worker.prototype.getHeapSnapshot
.
Globals Jump to heading
This is the list of Node globals that Deno supports. These globals are only
available in the npm
package scope. In your own code you can use them by
importing them from the relevant node:
module.
Unstable compatibility features Jump to heading
Node and npm compatibility is an ongoing project for the Deno team. As such, there are a number of unstable features aimed at improving compatibility that you may want to reference. Please check out the unstable feature flags documentation for options that may improve your project's compatibility with code written for Node.js.