Skip to main content
Deno 2 is finally here 🎉️
Learn more
Deno 1.45

Deno continues to evolve with Deno 1.45. The standout feature in this release is the introduction of workspaces, providing a robust solution for managing monorepos. This addition simplifies dependency management, configuration sharing, and module organization across large codebases. Alongside workspaces, this update includes improvements to Node.js compatibility, updates to deno install, the new deno init --lib command, the deprecation of deno vendor, and more.

To upgrade to Deno 1.45, run the following in your terminal:

deno upgrade

If Deno is not yet installed, run one of the following commands to install or learn how to install it here.

# Using Homebrew (macOS):
brew install deno

# Using Shell (macOS and Linux):
curl -fsSL https://deno.land/install.sh | sh

# Using PowerShell (Windows):
iwr https://deno.land/install.ps1 -useb | iex

What’s New in Deno 1.45

Workspace support

Deno v1.45 adds support for workspaces and monorepos. There are two forms of supported workspaces: Deno-first workspaces defined in deno.json and backwards-compatible npm workspaces.

Deno workspaces are straightforward. Configuration defined globally is applied to each member package but can be overridden by members. You can mix and match npm and Deno workspaces—an npm package inside a Deno workspace or vice versa.

Publishing workspace members to JSR is as easy as running deno publish. The standard library is a good example of how to use workspaces effectively.

To get started, define a "workspace" element inside your deno.json and list the member directories.

{
  "workspace": ["./add", "./subtract"]
}

npm workspaces also work seamlessly in Deno. Whether you’re including a Deno library in a larger npm workspace or an npm library in a larger Deno workspace, dependencies will correctly resolve.

To learn more about workspace support, visit the Deno Docs.

We will also host a one-hour livestream on YouTube on Tuesday, July 16, at 9 AM PT (UTC-7) to cover our new workspace support in detail and answer your questions. RSVP here.

Node.js compatibility improvements

Node-API support has been completely revamped, fixing many existing issues with packages like prisma, sqlite3, paper, duckdb, nodejs-polars.

Other Node.js compatibility improvements include:

Additionally, there are other impovements related to npm support:

Frozen lockfile

A new --frozen (alias --frozen-lockfile) flag has been added that controls the behavior of the lockfile.

You can use this flag to tell Deno to error out any time the lockfile gets out of date. This is especially useful in context of CI pipelines, where you should ensure that all the pushed code is up to date and there are no new or surprising changes to your dependencies.

When running a deno command with the --frozen flag, any attempts to update the lockfile with new contents will cause the command to exit with an error showing the modifications that would have been made.

For example, let’s say somewhere in your project you were importing npm:[email protected]. Then later down the line, someone copies a snippet of code from a slightly out of date AI chatbot that only knows about chalk version 5.2.0, so a file ends up with an import like:

import chalk from "npm:[email protected]";

Luckily, your CI pipeline has a test step with --frozen specified:

deno test --frozen --coverage

Instead of quietly adding a second (out of date) version of chalk to your dependency tree, it fails, showing that chalk 5.3.0 would’ve been added to your lockfile:

error: The lockfile is out of date. Run `deno cache --frozen=false` or rerun with `--frozen=false` to update it.
changes:
 5 | -      "npm:[email protected]": "npm:[email protected]"
 6 | -    },
 7 | -    "npm": {
 5 | +      "npm:[email protected]": "npm:[email protected]",
 6 | +      "npm:[email protected]": "npm:[email protected]"
 7 | +    },
 8 | +    "npm": {
 9 | +      "[email protected]": {
10 | +        "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==",
11 | +        "dependencies": {}
12 | +      },

If you intend to explicitly update your lockfile, you can specify --frozen=false, which will update the lockfile without error.

With the above setting, every dependency update will require running a command or a task with --frozen=false flag, making these updates intentional and explicit.

Finally, the --lock-write is now deprecated and will be removed in Deno 2. You can replace --lock-write usages with --frozen=false.

deno install updates

In Deno 2, the deno install subcommand will behave more like npm install to support common workflows. Currently in Deno, deno install <pkg> installs a binary package globally. In Deno 2, deno install <pkg> will install a package locally by default, adding a new dependency to the project (similar to deno add <pkg>) and caching it. In addition, deno install without an argument will cache local dependencies listed in package.json or an import map as well as set up a local node_modules directory, if applicable. To install globally, you’ll need to specify the --global (-g) flag: deno install --global <pkg>.

To try out the new install command in your projects, run with DENO_FUTURE=1:

DENO_FUTURE=1 deno install

with an argument, like deno add:

DENO_FUTURE=1 deno install @david/dax

We encourage you to try out the new deno install and report any issues you encounter!

npm lifecycle scripts support

Some scripts in package.json are special in that they are executed automatically by npm on certain operations. There are many lifecycle scripts supported by npm, but as a consumer of a package the main relavant scripts are pre/post install scripts, which are executed when a package is installed (i.e. normally during npm install).

Some packages rely on their install scripts to perform setup steps (for instance, downloading or building artifacts of native addons), and won’t work properly if they aren’t executed. Previously, Deno did not support executing lifecycle scripts, so this could result in confusing errors when using some packages, and there weren’t easy solutions.

Now, Deno supports running lifecycle scripts in deno cache (and DENO_FUTURE=1 deno install), and will warn if it detects that a package has a lifecycle script that hasn’t been run.

By specifying the --allow-scripts flag with deno cache (or DENO_FUTURE=1 deno install), you can opt into running lifecycle scripts for specific packages:

deno cache --allow-scripts=npm:duckdb main.ts

ℹ️ Note
Currently we only support lifecycle scripts when using a local node_modules directory ("nodeModulesDir": true in deno.json).

In the future we plan to add support for lifecycle scripts without node_modules, but this will be best-effort, as some packages rely on being in a node_modules directory.

deno init --lib - easily set up a new library

deno init subcommand was introduced in Deno v1.25 and allowed you to start a minimal scaffold for Deno project in a few keystrokes.

Since introduction of JSR users have been asking for a way to quickly start a project that will be published to JSR.

You can do just that with Deno v1.45 and deno init --lib:

✅ Project initialized

Run these commands to get started

  # Run the tests
  deno test

  # Run the tests and watch for file changes
  deno task dev

  # Publish to JSR (dry run)
  deno publish --dry-run

Just make sure to update name and version fields in the generated deno.json file before publishing!

deno vendor is now deprecated

deno vendor was added in Deno v1.19 to allow users to vendor all dependencies inside the project directory.

Since then, another way of vendoring dependencies was introduced in Deno v1.37 with --vendor flag or { "vendor": true } option in the config file.

This option received a lot of positive feedback and pointed out shortcomings and poor DX or deno vendor subcommand. With that in mind, deno vendor is now deprecated and scheduled to be removed in Deno 2.

Please migrate to using --vendor flag or vendor option in the config file.

deno test file discovery

deno test can automatically discover and run tests for files that match certain patterns:

  • File name ends with _test - eg. app_test.ts, component_test.tsx
  • File name ends with .test - eg. router.test.ts, controller.test.js
  • File name is test - eg. test.ts, test.js

To improve compatibility with wider ecosystem, deno test will now automatically discover and run files that are under __tests__ directory:

$ tree
.
├── __tests__
│   ├── integration.ts
│   └── unit.ts
└── main.ts

2 directories, 3 files

In Deno v1.44:

$ deno test
error: No test modules found

In Deno v1.45:

$ deno test
deno test
Check file:///Users/ib/dev/test_discovery/__tests__/integration.ts
Check file:///Users/ib/dev/test_discovery/__tests__/unit.ts
running 1 test from ./__tests__/integration.ts
integration test ... ok (0ms)
running 1 test from ./__tests__/unit.ts
unit test ... ok (0ms)

ok | 2 passed | 0 failed (11ms)

Blob.bytes()

Following up on changes from Deno v1.44 and updates to the Web File API specification, Blob.bytes() is now supported:

const jsonStr = JSON.stringify({ hello: "world" }, null, 2);

// Before:
const blob = new Blob([jsonStr], { type: "application/json" });
const buffer = new Uint8Array(await blob.arrayBuffer());

// After:
const blob = new Blob([jsonStr], { type: "application/json" });
const buffer = await blob.bytes();

Jupyter notebooks improvements

You can now use prompt and confirm API in Jupyter notebooks to provide more flexibility and interactivity.



To further improve Data Science ecosystem for JavaScript (and TypeScript) we’re aiming to add support for interactive widgets using JSX and React in the next release.

deno compile supports --env flag

--env flag was added in Deno v1.38, adding native support for loading env vars for the process from .env files.

With Deno v1.45 --env flag can be used to base in certain environmental variables into binaries produced with deno compile.

🛑 Caution
Keep in mind, that these env vars can still be read when inspecting contents of the shipped program, so use this feature with care. It’s probably not the best idea to ship production keys written into the binary.

When executing a program created with deno compile, all calls to Deno.env.get(<var_name>) for variables provided in the .env file, will return a value specified during compilation process, not the current variable on user system:

$ cat .env
HELLO_THERE=deno

$ cat main.ts
console.log("Hello there")
console.log(Deno.env.get("HELLO_THERE") + "!");

$ deno compile --env --allow-env main.ts
...

In Deno v1.44.4

HELLO_THERE="General Kenobi" ./main
Hello there
General Kenobi!

In Deno v1.45.0

HELLO_THERE="General Kenobi" ./main
Hello there
Deno!

More flexible language server

Previously, the VSCode extension could only read and incorporate the deno.json or deno.jsonc file located at the root of the workspace. The configuration from there would be applied to every open source file. This made certain monorepo configurations impossible.

1.45 makes the language server more independent of the root folder open in the editor. Configuration files in subdirectories are now detected, even if there are multiple. Each discovered deno.json or deno.jsonc will produce a separate scope with its own typechecking environment, module resolution and more. You can configure different entries for compilerOptions.libs or import modules which make augmentations to global types, these will not pollute the environment of other deno.json[c] scopes.

The Standard Library is closer to being stable

The Deno Standard Library offers a set of high quality packages that are audited by the core team and guaranteed to work with Deno.

As mentioned in our previous blog post, the Standard Library is currently undergoing stabilization efforts, with the goal of stabilizing 31 out of 38 packages.

To date, we’ve stabilized 13 packages:

  1. @std/assert
  2. @std/bytes
  3. @std/collections
  4. @std/crypto
  5. @std/data-structures
  6. @std/encoding
  7. @std/html
  8. @std/media-types
  9. @std/msgpack
  10. @std/path
  11. @std/regexp
  12. @std/toml
  13. @std/uuid

These packages have reached version 1.0.0, adhere to SemVer semantics and ensure the compatibility throughout their 1.x.x versions.

The remaining 18 packages have had their release candidate (RC) versions published (see the roadmap issue for list). If you’re currently using any of these packages, please consider testing the RC versions and sharing your feedback with us!

For more details on the stabilization timeline, please refer to the roadmap issue.

V8 12.7 and TypeScript 5.5.2

Deno 1.45 ships with V8 12.7 and TypeScript 5.5.2.

Try out Deno 2 features with DENO_FUTURE=1

We encourage you to try running your existing projects with DENO_FUTURE=1 environmetal variable, which enables Deno 2 features. We anticipate minimal to very low effort migration. If your experience is different share it with us.

Acknowledgments

We couldn’t build Deno without the help of our community! Whether by answering questions in our community Discord server or reporting bugs, we are incredibly grateful for your support. In particular, we’d like to thank the following people for their contributions to Deno 1.45: Adam Gregory, Andreas Kohn, Andrew Johnston, Filip Skokan, HasanAlrimawi, Kenta Moriuchi, Luca Bruno, Oliver Medhurst, Richard Carson, Tom Alcorn, Victor Turansky, Yazan AbdAl-Rahman, Zander Hill, Zebreus, muddlebee, safaa-mojahed, ud2.

Would you like to join the ranks of Deno contributors? Check out our contribution docs here, and we’ll see you on the list next time.

Believe it or not, the changes listed above still don’t tell you everything that got better in 1.45. You can view the full list of pull requests merged in Deno 1.45 on GitHub here.

Thank you for catching up with our 1.45 release, and we hope you love building with Deno!