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-ffipermission 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 withdeno 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
processis available everywhere, butBuffermust be imported fromnode:buffer.__dirnameand__filenameare replaced byimport.meta.dirnameandimport.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 tonpm run. Scripts that callnodedirectly 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
nodeModulesDirsetting 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
| Finding | What it means | Suggested next step |
|---|---|---|
| Pure-JavaScript dependencies, no unsupported modules | Good candidate | Run the full test suite under Deno on a branch |
| Native addons or install scripts | Workable with setup | Enable local node_modules, allow scripts per package, test on your real deploy target |
| Uses node:cluster or another unsupported module | Code change needed | Redesign that part or keep the service on Node |
| Heavy use of partial modules such as http2 or vm | Unknown risk | Check the per-method notes, write targeted tests |
| Build tools that walk node_modules directly | Likely friction | Try the hoisted layout or keep the build on Node |
| No clear reason to switch | Cost without benefit | Use Deno for the next new service instead |
How to run the trial
- Pick one service or script with good test coverage.
- Create a branch, add a deno.json, and run
deno installagainst the existing package.json. - Start with no permissions and add them one at a time as errors appear. The resulting list documents what the code really touches.
- Run the test suite and the app under realistic load, on the same kind of machine you deploy to.
- 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.