Skip to content
Nilay Kabariya

Entry No.053·Fixes·Updated ·8 min read

Bun "error: Cannot find module": every cause, tested

Bun prints the same Cannot find module error for six different problems. Each one reproduced on Bun 1.4.2 on Windows and Linux, with the fix that worked.

by Nilay#bun#typescript#monorepoFIXED

The error, verbatim

Jump to the fix ↓
error: Cannot find module '@mono/ui' from 'D:\nk-repro\bun-cnf\e-mono\apps\web\index.ts'

Bun v1.4.2 (Windows x64)
✓ Reproduced on Windows 11 Pro, and Linux (node:24 Docker image)

Tested on

Bun
1.4.2 (latest)
OS
Windows 11 Pro, and Linux (node:24 Docker image)
Node / TypeScript
24.14.0 / 5.9.3 and 7.0.2

✓ Re-verified on bun 1.4.2 (Linux + Windows): 16/16 checks still hold · results

Contents
  1. 1. Monorepo and workspace packages01
  2. 2. bun test and path aliases02
  3. 3. react/jsx-dev-runtime03
  4. 4. bun:sqlite and ‘bun’ imports outside Bun04
  5. 5. A package or file that isn’t there05
  6. 6. Works locally, fails on Linux06
  7. What didn’t work07
  8. How this was tested08

Bun uses one message, error: Cannot find module '<name>' from '<file>', for very different problems: a workspace package it hid on purpose, a test alias it never read, a JSX runtime you didn’t install. The message doesn’t tell you which one you have.

I reproduced each case on Bun 1.4.2 in a clean project, on Windows 11 and on Linux. Find yours in the table, then jump to its section.

You’re doing this What Bun prints Case
Importing a workspace package in a monorepo Cannot find module '@mono/ui' 1
Importing a package another workspace package depends on Cannot find package 'ms' 1
bun test with a path alias (~/, @/) Cannot find module '~/lib/math' 2
Running a .tsx or .jsx file Cannot find module 'react/jsx-dev-runtime' 3
Using bun:sqlite or import { $ } from 'bun' Cannot find module 'bun:sqlite', or TS2307 in your editor 4
A plain import of a package or file Cannot find package 'lodash' or Cannot find module './nope' 5
Code that works on Windows or macOS, fails in Docker or CI ENOENT reading "/tmp/b/utils.ts" 6

1. Monorepo and workspace packages

This is the case most people hit after moving a monorepo to Bun, and it comes from a default that changed. A new Bun workspace now installs with the isolated linker: my fresh bun install wrote "configVersion": 1 into bun.lock and linked each workspace package only into the node_modules of the packages that declare it. Nothing was hoisted to the root node_modules.

So an app can no longer import a package just because it happens to be in the repo, and it can no longer borrow a dependency that only a sibling package declares. Both worked with npm’s hoisting:

$ cd apps/web && bun run index.ts
error: Cannot find module '@mono/ui' from 'D:\nk-repro\bun-cnf\e-mono\apps\web\index.ts'

$ bun run phantom.ts
error: Cannot find package 'ms' from 'D:\nk-repro\bun-cnf\e-mono\apps\web\phantom.ts'

The second one is the sneaky one: ms was installed, but only packages/ui listed it.

Declare what each package imports, in that package’s own package.json:

cd apps/web
bun add @mono/ui@workspace:*
bun add ms

If you’d rather keep the old behaviour while you sort out the missing declarations, switch the linker back in bunfig.toml at the repo root, then delete node_modules and bun.lock and reinstall:

[install]
linker = "hoisted"

The same Cannot find module '@mono/ui' also appears when the package is declared but its package.json points main at a build folder that doesn’t exist yet ("main": "dist/index.js" before you’ve built it). Bun found the package, then found nothing to load.

Either build the package first, or point Bun at the source with an exports condition, which Bun reads before default:

{
  "name": "@mono/ui",
  "exports": {
    ".": {
      "bun": "./src/index.ts",
      "types": "./src/index.ts",
      "default": "./dist/index.js"
    }
  }
}

2. bun test and path aliases

If you’re moving tests from Jest, your aliases probably live in Jest’s moduleNameMapper. bun test doesn’t read Jest config, so the alias doesn’t exist:

$ bun test
tests\alias.test.ts:
# Unhandled error between tests
error: Cannot find module '~/lib/math' from 'D:\nk-repro\bun-cnf\f-test\tests\alias.test.ts'

Bun reads path aliases from tsconfig.json. Move the alias there:

{
  "compilerOptions": {
    "paths": { "~/*": ["./src/*"] }
  }
}

The Vitest side is not a problem: a test that imports describe, it and expect from "vitest" passed under bun test with Vitest not installed at all, because Bun handles that import itself.

3. react/jsx-dev-runtime

Bun compiles JSX for you, and the compiled code imports React’s JSX runtime. In a project with no React installed, a two-line .tsx file fails before it runs:

$ bun run index.tsx
error: Cannot find module 'react/jsx-dev-runtime' from 'D:\nk-repro\bun-cnf\c-jsx\index.tsx'

The name changes with the setup. With NODE_ENV=production it’s react/jsx-runtime. With "jsxImportSource": "preact" in tsconfig.json it’s preact/jsx-runtime.

Install the library the error names:

bun add react        # or: bun add preact, for preact/jsx-runtime

If you aren’t using React at all, check jsxImportSource in your tsconfig.json. It decides which package the error asks for.

4. bun:sqlite and ‘bun’ imports outside Bun

bun:sqlite, bun:test and import { $ } from 'bun' only exist inside the Bun runtime. Run the same file with anything else and it fails. These are the messages I got:

Ran with Message
node (ES module) ERR_UNSUPPORTED_ESM_URL_SCHEME … Received protocol 'bun:'
node (CommonJS) Error: Cannot find module 'bun:sqlite'
node, importing 'bun' Cannot find package 'bun' imported from D:\tmp\h2\shell.js
tsx ERR_UNSUPPORTED_ESM_URL_SCHEME, same as Node
tsc / your editor TS2307: Cannot find module 'bun:sqlite' or its corresponding type declarations.

The TypeScript one is only about types: the code runs fine under Bun.

For the editor and tsc error, install Bun’s types:

bun add -d @types/bun

For the runtime errors, the code has to run under Bun. That’s easy to get wrong with bun run dev: if the script calls a tool whose launcher starts with #!/usr/bin/env node (Next.js, Vite and most CLIs do), Bun respects that line and runs the tool in Node. Any bun:sqlite import inside it fails, even though you typed bun.

Bun has a flag for this, --bun, and on Windows it has a catch I had to track down: it only works when bun.exe is on the same drive as your temp folder. With --bun, Bun puts a stand-in node.exe in %TEMP%un-node-<revision> and links it to its own bun.exe. Windows can’t make that kind of link across drives, and Bun carries on silently with the real Node. That’s exactly the setup you get with Bun installed as a project dependency (npm i -D bun) in a project on D: while %TEMP% is on C:. There, even a script that was literally node -e "console.log(typeof Bun)" printed undefined. The same root cause is reported upstream as oven-sh/bun#44033, where it shows up loudly as bun: command not found: node on machines without Node. With Node installed, it fails silently instead. A fix (#44058) was still unmerged on October 8, 2026, and this check is re-run nightly, so this section will change when it ships.

Force Bun with --bun:

bun --bun run dev

If bun.exe is on a different drive from %TEMP%, bun --bun run dev, bun run --bun dev and [run] bun = true in bunfig.toml all still ran the tool in Node. Either put the flag inside the script itself:

{
  "scripts": {
    "dev": "bun --bun next dev"
  }
}

Or point your temp folder at Bun’s drive, for that terminal:

$env:TEMP = "D:	mp"; $env:TMP = "D:	mp"

Bun’s official Windows installer puts bun.exe in your user folder on C:, the same drive as %TEMP%, so that install doesn’t hit this.

5. A package or file that isn’t there

The plain cases, for completeness. Note the different wording: a bare package name says package, a path says module.

This is also why the error can seem random. In a folder with no node_modules anywhere above it, Bun auto-installs missing packages: the same lodash import, and the JSX file from case 3, ran fine there, because Bun downloaded the package on the fly. As soon as the project has a node_modules folder (any project after its first bun install), auto-install switches off and you get the error instead. A script that worked in a scratch folder can fail once it’s moved into a project.

error: Cannot find package 'lodash' from 'D:\nk-repro\bun-cnf\a-missing-pkg\index.ts'
error: Cannot find module './nope' from 'D:\nk-repro\bun-cnf\b-relative\missing.ts'

For a package, install it: bun add lodash, or bun install if it’s already in package.json. For a path, check the spelling against the file on disk, including its case (see the next section).

6. Works locally, fails on Linux

Windows and macOS don’t care about letter case in file names. Linux does. I imported ./utils while the file was Utils.ts. On Windows it ran and printed 3. Copied into the Linux container, Bun didn’t even say “Cannot find module”:

$ bun run index.ts
error: ENOENT reading "/tmp/b/utils.ts"

$ bun build index.ts --outdir out
error: File not found "/tmp/b/utils.ts"

There’s a trap in testing this: when I ran the project from a folder mounted from Windows into Docker, it still worked, because the files were still on Windows’ case-insensitive disk. It only failed once the files were copied into the container. A fresh git clone in CI behaves like the copy.

Make the import match the file name exactly (./Utils), or rename the file. On a case-insensitive disk, Git doesn’t pick up a rename that only changes case, so rename through Git:

git mv Utils.ts utils.ts

What didn’t work

I didn’t reproduce two searched variants: Cannot find module './cjs/index.cjs' from '' and paths starting with B:/~BUN/root/. Both come from compiled Bun executables (bun build --compile), the format some CLI tools ship in. If you see them from a tool you installed, it’s the tool’s own build, so update it or report it to its maintainers.

How this was tested

Bun 1.4.2 (the latest release, from npm) on Windows 11 Pro with Node 24.14.0, and on Linux in the official node:24 Docker image with Bun 1.4.2 installed from npm. Each case was a fresh folder:

  • a two-package workspace (packages/ui, apps/web) installed with the default linker, then --linker hoisted and the bunfig.toml setting
  • a Jest-style project run with bun test
  • .tsx files with no React, with Preact as jsxImportSource, and with NODE_ENV=production
  • bun:sqlite and 'bun' imports run with node, tsx and tsc (TypeScript 5.9.3 and 7.0.2)
  • a local CLI package whose bin starts with #!/usr/bin/env node, run through package.json scripts with and without --bun, with bun.exe on C: and on D: (%TEMP% on C:), and with TEMP moved to D:
  • a wrong-case import, run from a Windows-mounted folder and from a copy inside the container

Every message above was copied from those runs on October 8, 2026. These checks are re-run automatically against the newest Bun, on Windows and Linux; the date of the last run is shown at the top of this post.

The code for every case above is public, so you can run it yourself: bun-cannot-find-module in nk-repro.

— N.K., end of entry No.053

Useful? Pass it on:Post on XFollow @EmotionalMatter

Related entries

  1. No.012

    Bun vs Node.js 24 benchmark: startup, TypeScript and tests

    Bun started 1.7× faster, ran a TypeScript file 3× faster and finished the same test suite 5× faster. Node won the tight number-crunching loop. The HTTP test hit a limit of this machine, not of either runtime.

    TESTED3 min
  2. No.029

    Angular compilation initialization failed on TypeScript 7

    Angular 22 crashes on TypeScript 7 with reading 'Error', not the usual version warning. What actually failed, and the setup that builds with tsc 7, tested.

    > Application bundle generation failed. [0.412 seconds]

    FIXED2 min
  3. No.025

    Fix: TypeScript enum is not supported in strip-only mode

    Node's ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX for enum, parameter properties, namespace, export = and import =. Two ways to run it unchanged, both tested.

    > enum Color { Red, Green }

    FIXED3 min

Post card · Newsletter

Get the next fix in your inbox.

One short email when a new entry is published. No spam, never shared, and you can leave any time.

— Nilay

or follow by RSSor on X

By subscribing you agree to the privacy note. One click to leave.

tip: paste the exact error text