Toolchain
Transpiler
Section titled “Transpiler”Bun’s own parser and printer, compiled to WebAssembly. Output matches bun build --no-bundle --target=browser.
- ✅
.ts,.tsx,.jsx,.mts,.cts,.js,.mjs - ✅ JSX with Bun’s defaults (React automatic runtime)
- ✅ Legacy decorators with
experimentalDecoratorsandemitDecoratorMetadataintsconfig.json - ✅ Top-level
await - ❌
tsconfig.jsonpaths,baseUrl,jsx,jsxImportSourceandextendsare not read - ❌ No type checking
Module resolution
Section titled “Module resolution”- ✅ Relative imports, with
.ts .tsx .js .jsx .mjs .jsonandindex.*tried in that order - ✅ Packages from
node_modules, walking up folders:exports(nested conditions, arrays,./*patterns), thenmodule, thenmain - ✅ Conditions:
bun,node,import,development,defaultfor server code;browser,module,import,development,defaultfor code in the preview page - ✅
#importsfrom the nearestpackage.json - ✅ JSON imports
- ✅ CSS imported from code that goes through an HTML import (bundled)
- ✅
http:/https:imports are left to the browser rolldownis replaced by the playground’s own@rolldown/browser, since the native binding can’t load
An import that can’t be resolved shows cannot resolve "x" in the console.
CommonJS and require
Section titled “CommonJS and require”- ✅
.cjsfiles, and.jsfiles without ESM syntax in packages that aren’t"type": "module" - ✅
require("x")with a string literal. Modules run on firstrequire, as in Node; cycles see partial exports. - ✅ Named imports from CommonJS, found by a static scan (
exports.x =,module.exports = { … }, re-exports). Exports computed at runtime aren’t visible as named imports. - ✅
createRequire(import.meta.url)andimport.meta.requirewith string literals - ❌
require(variable)throws. So does arequirethat can’t be resolved, when it runs. - ❌
require.cache,require.main, native.nodeaddons
bun install
Section titled “bun install”Runs in the console (bun install, bun add, bun remove) and automatically when a project opens with missing dependencies.
- ✅ Packages from the npm registry, with Bun’s semver
- ✅
dependencies,devDependencies,optionalDependenciesand required peer dependencies - ✅
bun.lock(text format): exact versions, nestednode_modules, integrity checks. A stale lockfile logs a warning. - ✅ Optional packages limited to other platforms (native bindings) are skipped
- 🟡 Without a lockfile, the install is flat: the first version seen wins
- ❌ No
bun.lockis written.bun addrefuses to run when abun.lockexists. - ❌ No lifecycle scripts (
postinstall, …) - ❌ No git, tarball,
file:,workspace:ornpm:dependencies - ❌ Only
registry.npmjs.org;.npmrcisn’t read - ❌ Binary
bun.lockb
Bundler
Section titled “Bundler”Bun.build and HTML imports use Bun’s real bundler, compiled to WebAssembly (~10 MB, loaded on first use). See Bun.build for the supported options.
- Single-threaded; each build starts fresh
- HTML imports in
Bun.serveare built for the browser, without minification or source maps - If a build fails, errors go to the console and the page is served unbundled