Deno is probably not worth it right now
Tags: deno, node, typescript
Published: 2020-05-15 16:01:02

---
title: Deno is probably not worth it right now
published: true
description: A concise, critical overview of where Deno fits into the tooling landscape.
tags: deno, node, typescript
---

Deno has been riding a certain hype train since its [recent release][2], and it's important to look at it critically, first and foremost to avoid investing your limited time in a technology that might not pan out for your requirements and use case.

The title of this post already gives away the conclusion that Deno is *probably* not worth it, but the way I arrived at the conclusion was by trying to like Deno and to see how it could be used to its strengths. This post won't say anything very original, but the intent is to give a concise overview of where Deno fits into the [tooling landscape][3].

## Improved security

A highlight of Deno over Node.js and most other environments is the improved security model: programs don't just get blanket access to the resources available to the current user. I've seen the security improvements dismissed out of hand compared to other approaches like containerization, but it's actually a modern and welcome approach to limit access to resources by default; it should be an increasingly familiar approach going forward, and an another example of it is [WASI] using a [capability-based security][1] model.

## A fresh start for APIs

Outside of security by default, the other major advantage is to be able to break with the legacy aspects of Node.js APIs. To illustrate, this is how you can watch for file system changes using Deno:

```js
for await (const { kind, paths } of Deno.watchFs('.')) {
  console.log(kind, paths);
}
```

It takes advantage of ES2018 [async iteration][asit], and it even works at the top level without needing to be wrapped in an async function. Setting up the same (excepting the top level part) in Node.js would require boilerplate like this:

```js
const changes = new stream.Transform({ objectMode: true });
fs.watch('.', (event, pathname) => { changes.push({ event, pathname }); });
```

It creates a Node.js stream, which also implements the async iteration protocols and can be used with `for-await-of` loops, but you'd have to go out of your way to even know to do this, and usually it'd just be done using a plain callback, which at its worst can lead to the "pyramid of doom" problem. It's not a huge deal, but is an example of how a newer API can feel less "crusty" to use.

Deno also aims to avoid duplicating existing [web APIs][wap], such as `fetch()`, which means you can reuse the same API knowledge between platforms, and it should generally be a welcome idea.

## Dependency management is where it gets less fun

Deno is made by Ryan Dahl, who's also the original developer of Node.js, and, since the outset, the development of Deno has been couched in terms of fixing Node.js pain points, but the [talk that explains the motivation][pain] can also be (only somewhat uncharitably) summarized as "you could make the Node.js implementation simpler by not implementing features, like packages". It's not a compelling point to those relying on the features who would need to find workarounds.

Deno takes a page out of Go's approach to dependencies and doesn't provide a dependency manager like npm or Rust's cargo; instead of having special module resolution rules like with `require()`, modules are just loaded from URLs using the ECMAScript module format, and conventionally are re-exported from a `deps.ts` file instead of being listed in `package.json`.

There's still a way in Deno to create lock files, there's also an optional way to have [zero-installs](https://deno.land/x) like with Yarn by commiting a `$DENO_DIR`, and there's even something that [vaguely resembles][reg] a centralized registry, so it's all kind of similar while still being different and incompatible with existing tools and approaches in different ways.

## Compatibility and interoperability are crucial

Deno simplifies its implementation by skipping package management, but then it, for example, has a built-in test runner, which Node.js doesn't. Deno simplifies the Node.js APIs, but then it still needs to provide a complex [compatibility layer][compat], because there's a lot of existing and useful software using Node.js APIs. It's also adding a native plugin feature, although it'll probably never support Node.js native extensions.

The developer experience in all of this is a stream of "how do I…" and then often discovering that you either just don't, or that it's rudimentary compared to what you're used to (like the built-in Deno test runner compared to something like Jest), or that it half-works (I couldn't get the test runner work in watch mode using [Denon], which is meant to be the alternative to Nodemon).

For example, npm and Yarn provide [package scripts][scrip], which give a set way for users to discover and run commands, but in Deno you'd either have to find [Velociraptor][velo] (made less easy by the non-descriptive name of the tool), or use Makefiles or just shell scripts, and you'd also possibly be leaving out Windows users.

A list of issues like this could go on for a long time; some will have workarounds, others are just due to Deno just being released, but overall, if your goal is to get specific tasks done and not just use a "shiny new" tool, the lack of interoperability or compatibility skews the equation against Deno. 

## Conclusion

It can be helpful for Deno to "shake things up" and, for example, maybe make Node.js improve faster in aspects like modernizing its APIs, and to put the "security by default" model more solidly on the map, but overall Deno is a hard sell from a pragmatic standpoint. It reminds of the situation with Python 3, which brought improvements, but then took a long time to reach wide adoption due to it often just being easier to continue using Python 2.

Features like first-class support for TypeScript can also be a mixed bag (which I say as someone who generally prefers TypeScript), because use cases like prototyping or one-off scripts can actually benefit from dynamic typing, and it's also not necessarily useful to have type checking in the test runner if you already have it in the editor and the CI, but Deno doesn't yet have a way to selectively turn type checking off.

Even if you're not using Deno but are a library or tool author, you can look forward to possibly getting bug reports from a new, not fully compatible environment, or requests to support it, which isn't trivial (although the upside is that Deno should hopefully speed up ES module adoption).

The bottom line is that it's probably better that Deno exists, but its selling points are stretched thin by that it's still new, and that a lot of useful libraries and tools don't work and sometimes can't be ever expected to work.


[velo]: https://github.com/umbopepato/velociraptor
[scrip]: https://docs.npmjs.com/cli/run-script
[wap]: https://developer.mozilla.org/en-US/docs/Web/API
[1]: https://github.com/WebAssembly/WASI/blob/master/docs/DesignPrinciples.md#capability-based-security
[wasi]: https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/
[2]: https://deno.land/v1
[3]: https://tooling.js.org/
[asit]: https://2ality.com/2016/10/asynchronous-iteration.html
[pain]: https://youtu.be/M3BM9TB-8yA
[reg]: https://deno.land/x
[compat]: https://github.com/denoland/deno/issues/3403
[denon]: https://deno.land/x/denon/