Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/tutorials/migrate_node_project.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,4 @@ replaces several dev dependencies with zero configuration:
| `tsc --noEmit` | deno check |

For module resolution details, the full command cheatsheet, and tsconfig
migration, see the [Migrate from Node.js guide](/runtime/migrate/).
migration, see the [Migrate from Node.js guide](/runtime/migrate/migrate_from_node/).
6 changes: 5 additions & 1 deletion runtime/_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,14 @@ export const sidebar = [
href: "/runtime/lint_and_format/",
},
{
title: "Migrating from Node",
title: "Adopting Deno",
href: "/runtime/migrate/",
disclosure: true,
items: [
{
title: "Migrate from Node.js",
href: "/runtime/migrate/migrate_from_node/",
},
{
title: "Migrate from npm",
href: "/runtime/migrate/migrate_from_npm/",
Expand Down
2 changes: 1 addition & 1 deletion runtime/fundamentals/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ configuration from `deno.json`.
This is what lets you adopt Deno incrementally: keep running an app on Node
while using Deno as a faster drop-in package manager, run your existing scripts
with `deno task`, and add a `deno.json` for Deno's toolchain when you are ready.
The [Migrate from Node.js](/runtime/migrate/) guide walks through each step, and
The [Migrate from Node.js](/runtime/migrate/migrate_from_node/) guide walks through each step, and
[Node compatibility in Deno](/runtime/fundamentals/node/) covers how the runtime
maps Node's APIs and module resolution.

Expand Down
2 changes: 1 addition & 1 deletion runtime/fundamentals/node.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ install step) and try again.

For a full checklist, optional toolchain improvements, and a Node-to-Deno
command cheatsheet, see the
[Migrating from Node.js to Deno guide](/runtime/migrate/).
[Migrating from Node.js to Deno guide](/runtime/migrate/migrate_from_node/).

### Tools that spawn `node`

Expand Down
4 changes: 2 additions & 2 deletions runtime/fundamentals/typescript.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ in the configuration reference says what to do with each one. For most, the
answer is "delete it".

If you are moving a whole project over, the
[Migrating from Node.js](/runtime/migrate/) guide covers the rest (dependencies,
[Migrating from Node.js](/runtime/migrate/migrate_from_node/) guide covers the rest (dependencies,
`package.json`, npm scripts).

## Type checking
Expand Down Expand Up @@ -454,4 +454,4 @@ publishing to [JSR](https://jsr.io).
- Type-check the examples in your docs with
[documentation tests](/runtime/test/doc_tests/).
- Moving an existing project? Start with
[Migrating from Node.js](/runtime/migrate/).
[Migrating from Node.js](/runtime/migrate/migrate_from_node/).
2 changes: 1 addition & 1 deletion runtime/fundamentals/web_dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,4 +199,4 @@ deno run --allow-net server.ts
## Node projects

Deno will run your Node.js projects out the box. Check out our guide on
[migrating your Node.js project to Deno](/runtime/migrate/).
[migrating your Node.js project to Deno](/runtime/migrate/migrate_from_node/).
2 changes: 1 addition & 1 deletion runtime/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,6 @@ deno task # run scripts defined in deno.json
- **[Run code](/runtime/run/).** Servers, tasks, web APIs, and debugging.
- **[Manage packages](/runtime/packages/).** Dependencies, workspaces,
publishing.
- **[Migrate from Node.js](/runtime/migrate/).** Bring an existing project
- **[Migrate from Node.js](/runtime/migrate/migrate_from_node/).** Bring an existing project
across.
- **[Examples and tutorials](/examples/).** Ideas for what to build next.
271 changes: 93 additions & 178 deletions runtime/migrate/index.md
Original file line number Diff line number Diff line change
@@ -1,208 +1,123 @@
---
last_modified: 2026-06-25
title: "Migrate from Node.js"
description: "How to move a Node.js project to Deno: use Deno as a drop-in package manager, run your existing project and package.json scripts, understand how CommonJS and ES modules are resolved, and map your Node commands to Deno."
oldUrl:
- /runtime/fundamentals/migrate_from_node/
- /runtime/manual/node/migrate/
- /runtime/manual/references/cheatsheet/
- /runtime/manual/node/cheatsheet/
last_modified: 2026-07-02
title: "How to adopt Deno"
description: "A low-risk, step-by-step path for introducing Deno to an existing Node.js codebase and team: start with tooling, add a CI check alongside Node, use Deno as your package manager, pilot a project, then switch the runtime."
---

Most Node.js projects run in Deno **with no changes at all**. Deno reads your
`package.json`, installs and resolves the same npm dependencies, and runs both
CommonJS and ES modules, so in most cases you point Deno at your existing
project and it just works.
You don't have to adopt Deno all at once, and you don't need the whole team on
board to start. Deno is designed to slot into an existing Node.js and npm
codebase one piece at a time. Each step below is independently useful and fully
reversible, so you can stop at any point, keep your `package.json`, and still
come out ahead.

You can also adopt Deno incrementally: use it purely as a faster, drop-in
package manager for an app you still run with Node, run your existing
`package.json` scripts with `deno task`, or switch to Deno as the runtime and
pick up its built-in toolchain. This guide walks through each step.
This guide lays out a path from "try it on one file" to "team runtime,"
ordered from lowest risk to highest. Start at the top, go as far as makes sense,
and follow the links for the mechanics of each step.

## Use Deno as your package manager
## Step 1: Start with tooling, not the runtime

Deno is fully compatible with npm and `package.json`, so the easiest place to
start is dependency management, without changing how you run your code at all.
`deno install` reads your existing `package.json`, resolves the same npm
packages, and writes a `node_modules` directory, just like `npm install`:
The safest place to start changes nothing about how your application runs.
[`deno fmt`](/runtime/reference/cli/fmt/) and
[`deno lint`](/runtime/reference/cli/lint/) operate on your existing files,
need no configuration, and don't affect runtime behavior:

```sh
deno fmt
deno lint
```

Because Deno is a single binary with no dependencies to install, a teammate can
try these without adding anything to `package.json` or `node_modules`. This is
the easiest thing to put in front of a skeptical team: it replaces `prettier`
and `eslint` with one tool and zero config, and it touches nothing else.

## Step 2: Add a Deno check to CI, alongside Node

Once formatting and linting are useful locally, add them as a job next to your
existing Node jobs. Your build, test, and deploy steps stay exactly as they are:

```yaml
jobs:
deno-checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: denoland/setup-deno@v2
with:
deno-version: v2.x
- run: deno fmt --check
- run: deno lint
```

This is the first place the team sees Deno running in the pipeline, with no
runtime risk. For more CI patterns, see
[Continuous integration](/runtime/reference/continuous_integration/).

## Step 3: Use Deno as your package manager

The next step still leaves your app running on Node.
[`deno install`](/runtime/reference/cli/install/) reads the same `package.json`,
resolves the same npm packages, and writes a `node_modules` directory, just like
`npm install`:

```sh
cd my-node-app
deno install
```

From here you can keep running the app with Node and use Deno only as a faster,
more secure package manager. Deno reads dependencies from both `package.json`
and `deno.json`. For the full command mapping, what Deno does differently
(lifecycle scripts, auditing, lockfiles), and the caveats to know, see the guide
for the package manager you're coming from:
From here you can keep running the app with `node` and use Deno only as a
faster, more secure package manager. For the full command mapping and the
caveats to know, see the guide for the tool you're coming from:
[npm](/runtime/migrate/migrate_from_npm/),
[Yarn](/runtime/migrate/migrate_from_yarn/),
[pnpm](/runtime/migrate/migrate_from_pnpm/), or
[Bun](/runtime/migrate/migrate_from_bun/).

## Run your project with Deno
## Step 4: Run scripts and tests with Deno

To run an existing Node project with Deno, install its dependencies and run the
entrypoint:
With dependencies in place, you can start running things through Deno without
committing the whole app to it. [`deno task`](/runtime/reference/cli/task/) runs
the `scripts` in your `package.json`, the same way `npm run` does:

```sh
cd my-node-app
deno install
deno run main.js
deno task start
```

Expect one immediate difference from Node: Deno is
[secure by default](/runtime/fundamentals/security/), so the first time your app
touches the network, filesystem, or environment, Deno prompts for permission.
Grant what the app needs up front with flags (`deno run -N -R -E main.js`), or
run with `-A` for Node-equivalent behavior while migrating and tighten later.
See [Permissions](/runtime/reference/permissions/) for the full flag list.

If your `package.json` defines scripts, run them with
[`deno task`](/runtime/reference/cli/task/), the equivalent of `npm run`:

```json title="package.json"
{
"name": "my-project",
"scripts": {
"start": "node server.js"
}
}
```
You can also point [`deno test`](/runtime/reference/cli/test/) at a single test
file or directory to see how it handles a small, low-stakes slice of your suite
before moving the rest. Pick something contained here: a build script, an
internal tool, or one folder of tests, rather than the whole application.

```sh
deno task start
```
## Step 5: Pilot a project, then switch the runtime

Most code runs unchanged. The main thing to understand is how Deno decides
whether a file is CommonJS or an ES module, which follows your `package.json`.
That is covered next.
When the team is comfortable, run one project on the Deno runtime itself with
[`deno run`](/runtime/reference/cli/run/). Choose a low-stakes pilot first, such
as a new internal service, a CLI, or a script, rather than your most important
app. Because `package.json` still works and nothing is rewritten, you can revert
by going back to `node` if you hit a snag.

## CommonJS and ES modules
The mechanics of running an existing project on Deno, including permissions,
how CommonJS and ES modules are resolved, and the handful of errors most
projects hit on first run, are covered in detail in the
[Migrate from Node.js](/runtime/migrate/migrate_from_node/) guide. When the
pilot is stable, roll the same steps out to larger apps.

Deno runs both ES modules and CommonJS, and decides how to treat a file using
the same rules as Node.js:
## Why this is safe to try

- A `.cjs` file is **always** CommonJS, and a `.mjs` file is **always** an ES
module. The extension is enough.
- A `.js`, `.ts`, `.jsx`, or `.tsx` file is loaded as **CommonJS** when the
nearest `package.json` sets `"type": "commonjs"`, and as an **ES module**
otherwise. Deno walks up the directory tree to find that `package.json`, just
like Node.
Each argument here is one you can hand to a teammate who isn't sold yet:

```json title="package.json"
{
"type": "commonjs"
}
```
- **Reversible.** You keep your `package.json`, and Deno reads it directly.
Backing a step out means running `npm` or `node` again, with nothing to undo.
- **Incremental.** Every step is valuable on its own. Tooling-only adoption is a
complete, useful outcome even if you never switch the runtime.
- **No lock-in.** Deno doesn't require rewriting your code or maintaining a
parallel config. The same repository keeps working under both tools while you
decide.

So an existing CommonJS project keeps working: with `"type": "commonjs"` in
`package.json`, your `require()`-based `.js` files run under both Node and Deno.
CommonJS code needs its dependencies present in `node_modules` (set
`"nodeModulesDir": "auto"` in `deno.json`) and the usual
[permission flags](/runtime/fundamentals/security/).

You can also mix the two module systems: `require()` is available in `.cjs`
files or via `createRequire`, Deno's `require()` can load synchronous ES
modules, and you can `import` CommonJS files from ES modules. See
[CommonJS support](/runtime/fundamentals/node/#commonjs-support) for the details
and edge cases.

## Common errors and fixes

The handful of errors most Node projects hit on first run, and what they mean:

- **`NotCapable: Requires read access to "...", run again with the
--allow-read flag`**:
the permission sandbox at work. Grant the listed permission (`-R` here) or run
with `-A` until you're ready to scope permissions down.
- **`ReferenceError: require is not defined`**: Deno treated the file as an ES
module. Set `"type": "commonjs"` in `package.json`, or rename the file to
`.cjs`. See [CommonJS and ES modules](#commonjs-and-es-modules) above.
- **Cannot find module / missing `node_modules`**: run `deno install`. If your
tools expect a `node_modules` directory to exist, set
`"nodeModulesDir": "auto"` in `deno.json`.
- **A dependency's install/postinstall script didn't run** (native addons,
`node-gyp` builds): Deno does not run npm lifecycle scripts by default. Allow
them per package with `deno install --allow-scripts=npm:<pkg>`, or manage
approvals with
[`deno approve-scripts`](/runtime/reference/cli/approve_scripts/).
- **A `node:` API behaves differently or is missing**: check the
[Node API compatibility list](/runtime/reference/node_apis/) for status and
known gaps.

If you're migrating a framework app (Next.js, SvelteKit, Nuxt, and friends),
most run under Deno by replacing `npm run dev` with `deno task dev`. See
[Web development](/runtime/fundamentals/web_dev/) and the
[tutorials](/examples/) for framework-specific walkthroughs.

## Node to Deno Cheatsheet

In a Node project, many of these are separate packages you install and
configure: eslint, prettier, jest, ts-node, nodemon, nyc, tsc. In Deno they're
the same binary, with no extra dependencies and no config files to maintain. You
can keep your existing `package.json`, or move configuration into `deno.json`.

<div class="cheatsheet">

### Run and watch

| Node.js | Deno |
| ----------------- | ------------------ |
| `node file.js` | `deno file.js` |
| `ts-node file.ts` | `deno file.ts` |
| `node -e "…"` | `deno eval "…"` |
| `nodemon` | `deno run --watch` |

### Dependencies and scripts

| Node.js | Deno |
| ----------------------- | ----------------------- |
| `npm install` / `npm i` | `deno install` |
| `npm install -g <pkg>` | `deno install -g <pkg>` |
| `npm run <script>` | `deno task <script>` |
| `npm explain <pkg>` | `deno why <pkg>` |

### Quality and testing (built in, no install or config)

| Node.js | Deno |
| -------------------------------- | --------------- |
| `eslint` | `deno lint` |
| `prettier` | `deno fmt` |
| `jest` / `mocha` / `ava` / `tap` | `deno test` |
| `nyc` / `c8` / `istanbul` | `deno coverage` |
| benchmark libraries | `deno bench` |

### TypeScript, docs, and builds

| Node.js | Deno |
| -------------- | -------------- |
| `tsc` | `deno check` ¹ |
| `typedoc` | `deno doc` |
| `nexe` / `pkg` | `deno compile` |

¹ TypeScript runs directly: there's no build step. `deno check` type-checks
without emitting, and the compiler is built into the `deno` binary.

### Toolchain

| Node.js | Deno |
| ------------------- | ---------------- |
| `tsserver` | `deno lsp` |
| `nvm` / `n` / `fnm` | `deno upgrade` ² |

² `deno upgrade` updates the single installed binary and can pin any release
(`deno upgrade 2.1.0`); unlike `nvm`, it doesn't keep multiple versions
installed side by side.

</div>

## Keep going
## Next steps

- **[Migrate from Node.js](/runtime/migrate/migrate_from_node/).** The full,
hands-on guide to running an existing Node project on the Deno runtime.
- **[Node.js and npm compatibility](/runtime/fundamentals/node/).** What's
supported (`node:` built-ins, npm packages, globals) and the known gaps.
- **[Node API compatibility list](/runtime/reference/node_apis/).** Per-module
support status for every `node:` built-in.
- **[Migrating your tsconfig.json](/runtime/reference/ts_config_migration/).**
Map `tsconfig.json` options onto `deno.json`.
supported and the known gaps.
- **[Use Deno in an existing Node.js project](/examples/migrate_node_project_tutorial/).**
A step-by-step tutorial version of the migration path.
2 changes: 1 addition & 1 deletion runtime/migrate/migrate_from_bun.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ A few Bun features have no Deno counterpart, so plan around them:

## Keep going

- **[Migrate from Node.js](/runtime/migrate/).** Much of it applies to Bun
- **[Migrate from Node.js](/runtime/migrate/migrate_from_node/).** Much of it applies to Bun
projects too, including how CommonJS and ES modules are resolved.
- **[Security and permissions](/runtime/fundamentals/security/).** How the
sandbox works and which flags to grant.
Expand Down
Loading
Loading