Node.js is the de facto JavaScript runtime for use on servers and local machines. It’s well-liked, versatile, and supported by a strong community. Deno is a newer runtime that aims to address some of Node.js’ shortcomings. Here’s where Deno is hoping to improve.
The Basics
Historically JavaScript was consigned to the web. Runtimes like Node.js have expanded the environments a JavaScript developer can target, making it feasible to build backend systems in the language.
Both Node.js and Deno are built atop the V8 JavaScript engine used by the Chrome browser. Node.js was founded in 2009 while Deno came along in 2018. Both projects were created by Ryan Dahl. Deno is Dahl’s attempt to remake Node.js using lessons from the first ten years.
Deno focuses on shipping a lightweight runtime that’s secure by design. It’s also got built-in support for TypeScript, the Microsoft-led typed superset of JavaScript that’s becoming increasingly popular across the ecosystem. Straightaway this makes Deno a better candidate for people who prefer to work with the type protections TypeScript provides.
Security and Permissions
A large part of the Deno premise is founded on security. This extends down to the language it’s written in: although both Node.js and Deno use V8, Deno eschews Node’s C++ for the more modern Rust language. Rust offers similar performance levels but with greater safety.
Deno features a strict permissions system that limits the capabilities made available to processes. They have no access to the network, filesystem, or outside environment until access is explicitly granted. By contrast, anything executed with Node.js can automatically use all three.
The opt-in process for scripts that do need access offers the choice of command-line flags or a runtime permissions prompt. Flags can be really granular, such as –allow-read=/tmp to permit filesystem access to a single directory. This empowers users and administrators to restrict programs to the minimum level of access they require.
Decentralized Package Management
Love it or hate it, npm (the Node Package Manager) has become an integral part of modern JavaScript development for most. npm’s a separate project to Node.js which could theoretically be distributed with Deno too. Deno doesn’t include it though and there’s no support for using packages from a node_modules directory.
Node.js favors CommonJS modules as its module support predates the addition of native ES6 modules to the JavaScript standard. Deno requires the use of ES-style imports and allows the use of modules at arbitrary remote URLs:
Deno automatically downloads and compiles the module the first time you run your program. It’ll then cache the result; just like an npm install, Deno programs will work when offline after a one-time download has been performed.
This approach was chosen in lieu of the centralized distribution of npm packages. Node.js programs are usually inextricably bound to software in the central npm registry. If npm were to be unavailable, developers worldwide would be unable to acquire their dependencies. Deno advocates hosting modules anywhere and arbitrary HTTP URIs become acceptable “registries.”
Standard Library and Node.js Interop
Deno includes a sizable standard library of modules reviewed by the core development team. Each module in the standard library is standalone with no external dependencies. The library is versioned and distributed independently of Deno releases; just like third-party modules, you need to use URLs to import components in your code.
One of the modules within the standard library is a compatibility layer for Node.js. This adds implementations of many of the key modules included with Node. It makes it easier to transition software written for Node to the Deno runtime.
Deno 1.15, released in October 2021, further enhanced the compatibility with Node. A new CLI flag, –compat, instructs Deno to configure the environment with all the global variables provided by Node. Built-ins like process aren’t supported by Deno but using –compat makes them available on an opt-in basis.
Which Should I Use?
Deno’s unlikely to replace Node.js anytime soon, if ever. While Node isn’t perfect, as Deno aptly highlights, it has the advantage of a massive community and very strong adoption. Migrating from Node.js to Deno isn’t trivial; although the core JavaScript is unchanged, you’d need to account for the differences in global variables, standard library components, and package management.
For the foreseeable future, Node.js is probably still your best bet for general-purpose JavaScript programs. There’s a wealth of frameworks, libraries, and tutorials available. Node’s not stood still over the past few years either – there’s now stable support for ES6 modules and other language features like top-level await.
Deno is a better option for new from-scratch projects at the cutting edge of the JavaScript ecosystem. If you’re using TypeScript, want a decentralized package management system, or you need strong security controls, Deno is the more suitable option.
While Deno’s attracted a lot of interest and hype in the three years since its announcement, that’s not yet converted into wide scale real-world usage. That doesn’t mean you shouldn’t use it though – Deno’s now stable and backed by a strong standard library.
It’s best to assess each of your new projects against the individual characteristics of Node.js and Deno, then make a judgement as to which you use. Trying to use the same runtime for every codebase could mean you miss out on some of the strengths of the other platform.
Summary
Deno is a young JavaScript runtime from the original developer of Node.js. It addresses many of the shortcomings of Node, eschewing centralized package management for a fully distributed model, adding a fine-grained runtime-level permissions model, and integrating TypeScript as a first-class citizen.
Although Deno’s not yet got the same reach as Node.js, it’s already a worthwhile contender for your next project. This is especially true if you want to make the switch to TypeScript or are developing a security-critical workload.
Now that Deno’s actively adding enhanced Node.js compatibility, it’s possible that interest and adoption will begin to grow. The Deno team is working towards full Node emulation which could provide a viable transition pathway for existing projects.
Deno’s momentum may ultimately come from external factors, such as the strong growth in the TypeScript ecosystem. Deno’s standard library is written in TypeScript, demonstrating its significance to the project. Although Node.js and TypeScript can be readily integrated, you need an intermediary build stage to convert TypeScript source into JavaScript which Node can execute. Deno shortens the feedback loop, offering an improved developer experience with TypeScript integrated from the outset.