Auto-install

If no node_modules directory is found in the working directory or higher, Bun will abandon Node.js-style module resolution in favor of the Bun module resolution algorithm.

Under Bun-style module resolution, all imported packages are auto-installed on the fly into a global module cache during execution (the same cache used by bun install).

import { foo } from "foo"; // install `latest` version

foo();

The first time you run this script, Bun will auto-install "foo" and cache it. The next time you run the script, it will use the cached version.

Version resolution

Image for: Version resolution

To determine which version to install, Bun follows the following algorithm:

  1. Check for a bun.lock file in the project root. If it exists, use the version specified in the lockfile.
  2. Otherwise, scan up the tree for a package.json that includes "foo" as a dependency. If found, use the specified semver version or version range.
  3. Otherwise, use latest.

Cache behavior

Image for: Cache behavior

Once a version or version range has been determined, Bun will:

  1. Check the module cache for a compatible version. If one exists, use it.
  2. When resolving latest, Bun will check if package@latest has been downloaded and cached in the last 24 hours. If so, use it.
  3. Otherwise, download and install the appropriate version from the npm registry.

Installation

Image for: Installation

Packages are installed and cached into <cache>/<pkg>@<version>, so multiple versions of the same package can be cached at once. Additionally, a symlink is created under <cache>/<pkg>/<version> to make it faster to look up all versions of a package that exist in the cache.

Version specifiers

Image for: Version specifiers

This entire resolution algorithm can be short-circuited by specifying a version or version range directly in your import statement.

import { z } from "zod@3.0.0"; // specific version
import { z } from "zod@next"; // npm tag
import { z } from "zod@^3.20.0"; // semver range

Benefits

Image for: Benefits

This auto-installation approach is useful for a few reasons:

  • Space efficiency — Each version of a dependency only exists in one place on disk. This is a huge space and time savings compared to redundant per-project installations.
  • Portability — To share simple scripts and gists, your source file is self-contained. No need to zip together a directory containing your code and config files. With version specifiers in import statements, even a package.json isn't necessary.
  • Convenience — There's no need to run npm install or bun install before running a file or script. Just bun run it.
  • Backwards compatibility — Because Bun still respects the versions specified in package.json if one exists, you can switch to Bun-style resolution with a single command: rm -rf node_modules.

Limitations

Image for: Limitations
  • No Intellisense. TypeScript auto-completion in IDEs relies on the existence of type declaration files inside node_modules. We are investigating various solutions to this.
  • No patch-package support

FAQ

Image for: FAQ

How is this different from what pnpm does?

How is this different from Yarn Plug'N'Play does?

How is this different from what Deno does?