automotif

all articles
tech · 5 min read

Evaluating Deno for a Node.js project: a compatibility checklist

Assess a move from Node.js to Deno with dependency, runtime and deployment checks, instead of assuming every npm package will work unchanged.

Deno 2 shipped in October 2024 with much better support for Node.js and npm, and the 2.x line has kept closing gaps since. Better support is not the same as identical behavior. If you run a Node.js project and are wondering whether to move it to Deno, this checklist helps you find out what would break before you commit to the switch.

Where Deno stands today

At the time of writing, the current major version is Deno 2: the latest release on the project's GitHub releases page is 2.9.7, published in September 2026. Check the releases page for the version you will actually test against, because compatibility notes in the docs are tied to specific minor versions.

Deno's own compatibility page is direct about the state of things. It says "Most pure-JavaScript npm packages work without changes," and that as of Deno 2.8, "over 75% of Node's own test suite passes in Deno." It also lists the limits: "some APIs are partial," "packages with native addons need a local node_modules directory," and "a few tools assume npm's exact on-disk layout."

That is a useful starting point, and also the reason to test rather than assume. A project is only as compatible as its least compatible dependency.

Decide why you are evaluating Deno

Write down the reason before you start. Common ones:

  • You want the built-in permission system, so scripts cannot read files or reach the network unless allowed.
  • You want built-in tooling (formatter, linter, test runner, TypeScript without a separate build step) instead of assembling it yourself.
  • A new service is starting and you are choosing a runtime, rather than migrating an existing one.

If the reason is vague, the cost of a migration is hard to justify. A new, small service is a far cheaper test than moving your main application.

Checklist 1: dependencies

Start here, because this is where most surprises are.

  • List every direct dependency in package.json and note which ones include native code. Deno supports Node-API native addons, but only when a local node_modules directory exists and the --allow-ffi permission is granted.
  • Find packages that rely on install scripts. Deno does not run lifecycle scripts such as postinstall by default. You allow them per package, for example deno install --allow-scripts=npm:duckdb, or approve them interactively with deno approve-scripts. Without this, packages that build native code on install fail at runtime.
  • Find tools that assume npm's exact folder layout: some bundlers, code generators and plugins that walk node_modules directly.
  • Check whether you use a private registry. Deno reads registry settings from .npmrc, including auth tokens.
  • Look for CommonJS-only packages and your own .js files written as CommonJS. Deno supports CommonJS in .cjs files and in .js files inside a package marked "type": "commonjs", but does not detect CommonJS from file contents unless you pass --unstable-detect-cjs.

Checklist 2: Node built-in APIs

Deno's Node APIs reference lists every node: module with a status. At the time of checking, 16 of 44 modules were marked partially supported and 6 unsupported.

  • Unsupported: cluster, domain, repl, sea, trace_events, wasi. If your app forks workers with node:cluster, plan a different approach; the docs say its exports are non-functional stubs.
  • Partially supported includes http, http2, https, net, tls, dns, vm, worker_threads, zlib, inspector and others. "Partial" can mean a single unused method or something your app depends on, so read the notes for each module you import.

Search your code and your dependencies' code for node: imports and bare built-in names, then compare against the list:

grep -rhoE "from ['\"](node:)?(cluster|domain|repl|trace_events|wasi|http2|vm|worker_threads|inspector)['\"]" src/ | sort | uniq -c

This only catches your own code. Dependencies are better tested by running them.

Checklist 3: globals and runtime behavior

  • process is available everywhere, but Buffer must be imported from node:buffer.
  • __dirname and __filename are replaced by import.meta.dirname and import.meta.filename. Code that reads them in ES modules needs updating.
  • npm packages run under Deno's permission system. A package that writes temporary files or reads environment variables needs those permissions granted. Decide which permissions each entry point really needs, rather than granting everything to get past errors, which removes the main safety benefit.
  • Scripts in package.json run with deno task, similar to npm run. Scripts that call node directly still run the Node binary, so they are not actually testing Deno.

Checklist 4: build, test and deploy

  • Decide how node_modules is handled. The nodeModulesDir setting in deno.json accepts "none", "auto" and "manual". Native addons and layout-sensitive tools need a local directory.
  • Run your existing test suite under Deno. If it depends on a Node-specific test runner, budget time to port or run it.
  • Check your hosting. Your platform must support the Deno version you test with, or let you supply your own container image.
  • Check observability: logging, error tracking and APM agents often patch Node internals and may rely on partially supported modules.
  • Keep the Node.js build working until Deno has run in production for a while. A rollback should be a config change, not a project.

A decision table

FindingWhat it meansSuggested next step
Pure-JavaScript dependencies, no unsupported modulesGood candidateRun the full test suite under Deno on a branch
Native addons or install scriptsWorkable with setupEnable local node_modules, allow scripts per package, test on your real deploy target
Uses node:cluster or another unsupported moduleCode change neededRedesign that part or keep the service on Node
Heavy use of partial modules such as http2 or vmUnknown riskCheck the per-method notes, write targeted tests
Build tools that walk node_modules directlyLikely frictionTry the hoisted layout or keep the build on Node
No clear reason to switchCost without benefitUse Deno for the next new service instead

How to run the trial

  1. Pick one service or script with good test coverage.
  2. Create a branch, add a deno.json, and run deno install against the existing package.json.
  3. Start with no permissions and add them one at a time as errors appear. The resulting list documents what the code really touches.
  4. Run the test suite and the app under realistic load, on the same kind of machine you deploy to.
  5. Write down every workaround. If the list is long, that is your answer for now.

Revisit the result when a new Deno minor version lands, since the compatibility notes change between releases.

Where automotif fits

Most of the businesses we work with do not need to change runtimes. Where Deno does come up, it is usually for a small script or service that sits between other tools, and that falls under automation builds: we can help decide whether a given job belongs in n8n, Make or Zapier, or needs a small piece of code, and on which runtime. To talk through a specific case, book a free call of 30 to 60 minutes.

Sources