From 54c4edb59a9a6973b68cf50cc07e0af2be477619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Thu, 2 Jul 2026 09:47:11 +0200 Subject: [PATCH] docs: add 'How to adopt Deno' guide for incremental team adoption Repurpose the top-level /runtime/migrate/ page as a phased, low-risk adoption path (tooling -> CI -> package manager -> pilot -> runtime) and move the Node.js migration mechanics to a sibling page. Retarget inbound 'Migrate from Node.js' links to the moved page and rename the sidebar group to 'Adopting Deno'. --- examples/tutorials/migrate_node_project.md | 2 +- runtime/_data.ts | 6 +- runtime/fundamentals/configuration.md | 2 +- runtime/fundamentals/node.md | 2 +- runtime/fundamentals/typescript.md | 4 +- runtime/fundamentals/web_dev.md | 2 +- runtime/index.md | 2 +- runtime/migrate/index.md | 271 +++++++-------------- runtime/migrate/migrate_from_bun.md | 2 +- runtime/migrate/migrate_from_node.md | 208 ++++++++++++++++ runtime/migrate/migrate_from_npm.md | 2 +- runtime/migrate/migrate_from_pnpm.md | 2 +- runtime/migrate/migrate_from_yarn.md | 2 +- runtime/reference/migration_guide.md | 2 +- 14 files changed, 318 insertions(+), 191 deletions(-) create mode 100644 runtime/migrate/migrate_from_node.md diff --git a/examples/tutorials/migrate_node_project.md b/examples/tutorials/migrate_node_project.md index a2b5be7b2..85329a0c1 100644 --- a/examples/tutorials/migrate_node_project.md +++ b/examples/tutorials/migrate_node_project.md @@ -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/). diff --git a/runtime/_data.ts b/runtime/_data.ts index 53fd32e8f..878cbace9 100644 --- a/runtime/_data.ts +++ b/runtime/_data.ts @@ -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/", diff --git a/runtime/fundamentals/configuration.md b/runtime/fundamentals/configuration.md index 6abd00e6e..218ae0f6b 100644 --- a/runtime/fundamentals/configuration.md +++ b/runtime/fundamentals/configuration.md @@ -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. diff --git a/runtime/fundamentals/node.md b/runtime/fundamentals/node.md index a286ad958..61ba0071a 100644 --- a/runtime/fundamentals/node.md +++ b/runtime/fundamentals/node.md @@ -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` diff --git a/runtime/fundamentals/typescript.md b/runtime/fundamentals/typescript.md index c88d9ebf2..42c5a844d 100644 --- a/runtime/fundamentals/typescript.md +++ b/runtime/fundamentals/typescript.md @@ -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 @@ -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/). diff --git a/runtime/fundamentals/web_dev.md b/runtime/fundamentals/web_dev.md index 2fa573057..19e76a6cb 100644 --- a/runtime/fundamentals/web_dev.md +++ b/runtime/fundamentals/web_dev.md @@ -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/). diff --git a/runtime/index.md b/runtime/index.md index 77db2ed3f..955749443 100644 --- a/runtime/index.md +++ b/runtime/index.md @@ -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. diff --git a/runtime/migrate/index.md b/runtime/migrate/index.md index df8951df3..124a77839 100644 --- a/runtime/migrate/index.md +++ b/runtime/migrate/index.md @@ -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:`, 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`. - -
- -### 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 ` | `deno install -g ` | -| `npm run