Skip to main content
Deno 1.28 Release Notes

Deno 1.28: Featuring 1.3 Million New Modules

We’re excited to announce that Deno 1.28 stabilizes npm compatibility, which means you can now import over 1.3 million npm modules in Deno. Building apps will be easier and more secure than ever, now that you can use your favorite persistent data modules such as Prisma, Mongoose, and MySQL, as well as frontend frameworks such as React, Vue, etc.

Using npm is easier and safer with Deno. Deno’s built-in toolchain, first-class std library, and robust IDE support means you can be productive, faster. And Deno’s secure-by-default, opt-in permissions model means spending less time worrying about suspicious packages and more time shipping product.

Deno maintains that modern JavaScript should be built with ES Modules and web standard APIs. This release does not change that. Importing npm modules is done through URLs in a standard compliant fashion - we continue to move towards a browser-compatible future, where you’re using web APIs such as fetch, Request, and Response. Now, Deno is taking npm a step forward by allowing you to access your favorite modules in a modern, secure programming environment.

To help you get started using npm modules with Deno, we’ll be publishing resources, how-to guides, and more every day this week. Be sure to follow our Twitter and subscribe to our YouTube to follow along.

In this post:

Installing or Upgrading Deno

If you already have Deno installed, you can upgrade to 1.28 by running:

deno upgrade

If you are installing Deno for the first time:

# MacOS and Linux
curl -fsSL | sh

# Windows
irm | iex

Click here for more installation options.

Using npm

You can use npm packages by importing an npm: specifier.

In an import statement:

import { chalk } from "npm:chalk@5";

Or map a bare specifier to an npm specifier in an import map:

  "imports": {
    "chalk": "npm:chalk@5"

You can also run npm scripts or CLIs using Deno:

deno run --allow-env --allow-read npm:create-vite-extra

You can even execute npm packages with subcommands like this:

deno run npm:<package_name> <subcommand>

For example, the equivalent of npx prisma init in Deno is:

deno run npm:prisma init


While npm has made software easily usable and shareable, the unchecked approach to installing and running dependencies has made Node and npm susceptible to supply chain attacks. Through typosquatting, social engineering, and other exploits, malicious modules can be uploaded and then installed into production Node applications, compromising millions of users and their sensitive data.

Instead of allowing untrusted, third-party code to have access to your entire system, Deno’s secure-by-default approach can inform and restrict you when your dependencies attempt to access the system.

deno run npm:install-malware
⚠️  ┌ Deno requests write access to /usr/bin/.
   ├ Requested by `install-malware`
   ├ Run again with --allow-write to bypass this prompt.
   └ Allow? [y/n] (y = yes, allow; n = no, deny) >

Learn more about Deno’s opt-in permissions system.

No package.json

Using npm with Deno is simpler:

  • No npm install step: modules are installed the first time you run your program.
  • No package.json: less boilerplate noise cluttering your code base.
  • No node_modules folder by default (use --node-modules-dir for backwards compatibility). Modules are cached once in a special global directory.

Be productive immediately with Deno. With a built-in toolchain (including tester, formatter, linter, and more) and native TypeScript support, you can skip installing and configuring dependencies and dive right into the code.

Ongoing Work

Our aim is to make as many npm modules compatible with Deno as possible. Some modules may not be compatible (yet) due to some edge cases we haven’t come across, post-install scripts, or assumptions a few packages make about executing in a folder with a typical Node setup (e.g. assuming a package.json exists in the current working directory).

We’ll be working hard over the next few months to address these issues and improve our compatibility. For example, we’ve currently repurposed some of Node’s test suites to ensure our Node compatibility layer (e.g. modules like fs) works the same as Node’s and we’ll be expanding this coverage. We’re also actively fixing any edge cases surfaced by our community.

Some subcommands in Deno like deno compile do not yet work with npm modules. This work is being tracked in deno#15960.

To help us increase compatibility with npm, if you run into any problems using npm with Deno, please open an issue. We’re confident that with more usage, we’ll close most of the remaining compatibility gaps.

Auto discovery of the lock file

Deno has had support for lock files since v1.0, however the experience of using them left much to be desired - it was always a user’s responsibility to provide the --lock=<filename> flag to use a lockfile. We recognize that this situation led to many users not using a lock file at all.

Starting with Deno v1.28, the lock file will be automatically discovered and used if a configuration file (deno.json(c)) is discovered. In such case, a lock file will automatically be created (if one doesn’t exist yet), next to the configuration file, with the deno.lock name. The lock file will be automatically and additively updated if new dependencies become part of the module graph.

As a consequence, the --lock-write flag’s behavior has expanded for this auto-discovery scenario - instead of needing to pass this flag to update the lock file, it now can be used to force the generation of the lock file from scratch.

If you wish to disable automatic discovery of the lock file, you can use the --no-lock flag.

Additionally, the --lock flag no longer requires an argument by default anymore - if it is omitted, then Deno will default to ./deno.lock.

Changes to Deno APIs


The following APIs have been stabilized in this release and no longer require the --unstable flag to be used.

  • Deno.bench()
  • Deno.gid()
  • Deno.networkInterfaces()
  • Deno.systemMemoryInfo()
  • Deno.uid()

New unstable Deno.Command API

This release adds a new unified Deno.Command API to supersede the unstable Deno.spawn, Deno.spawnSync, and Deno.spawnChild APIs.

Basic async usage:

let c = new Deno.Command("echo", { args: ["foo"] });
let { stdout, stderr } = await c.output();

Basic sync usage:

let c = new Deno.Command("echo", { args: ["foo"] });
let { stdout, stderr } = c.outputSync();

Advanced async usage (with streaming):

const c = new Deno.Command("cat", { stdin: "piped" });
// open a file and pipe input from `cat` program to the file
const file = await"output.txt", { write: true });
await c.stdout.pipeTo(file.writable);

const stdin = c.stdin.getWriter();
await stdin.write(new TextEncoder().encode("foobar"));
await stdin.close();

const s = await c.status;

V8 10.9

This release upgrades to the latest release of V8 (10.9, previously 10.8). Mostly these are internal improvements but also includes a few public facing API changes:

A full list of changes between 10.8 and 10.9 is here.

Manual rewrite

As Deno has grown, so too has the Manual. We continuously added things here and there; overtime this has led it to become a bit untidy. In this release, we’ve done a full refactoring of the table of contents and prose to be simpler and more organized. We’ve even added an entire section dedicated to using npm.

There’s always room for improvement in documentation - if you see an area that could be improved please submit a PR to denoland/manual.

Launch Week

To demonstrate what you can now build with npm and Deno, we will be releasing tutorials, how-to guides, video walkthroughs on our YouTube, and other helpful resources every day this week.

And if you’re using Deno in a commercial setting and have any technical questions, please sign up for Office Hours, where you can have access to our engineers, who’ll help unblock you for 30 minutes.

Follow our Twitter and subscribe to our YouTube so you don’t miss out on anything!