Skip to main content
The Bun bundler has a set of built-in loaders.
As a rule of thumb: the bundler and the runtime both support the same set of file types by default.
.js .cjs .mjs .mts .cts .ts .tsx .jsx .css .json .jsonc .toml .yaml .yml .txt .wasm .node .html .sh Bun uses the file extension to choose which built-in loader parses the file. Every loader has a name, such as js, tsx, or json. Plugins that extend Bun with custom loaders refer to these names. To specify a loader explicitly, use the 'type' import attribute.
https://mintcdn.com/bun-1dd33a4e/JUhaF6Mf68z_zHyy/icons/typescript.svg?fit=max&auto=format&n=JUhaF6Mf68z_zHyy&q=85&s=7ac549adaea8d5487d8fbd58cc3ea35bindex.ts
import my_toml from "./my_file" with { type: "toml" };
// or with dynamic imports
const { default: my_toml } = await import("./my_file", { with: { type: "toml" } });

Built-in loaders

js

JavaScript loader. Default for .cjs and .mjs. Parses the code and applies a set of default transforms like dead-code elimination and tree shaking. Bun does not down-convert syntax.

jsx

JavaScript + JSX loader. Default for .js and .jsx. Same as the js loader, but JSX syntax is supported. By default, JSX is down-converted to plain JavaScript; the exact output depends on the jsx* compiler options in your tsconfig.json. See the TypeScript documentation on JSX.

ts

TypeScript loader. Default for .ts, .mts, and .cts. Strips out all TypeScript syntax, then behaves identically to the js loader. Bun does not perform typechecking.

tsx

TypeScript + JSX loader. Default for .tsx. Transpiles both TypeScript and JSX to vanilla JavaScript.

json

JSON loader. Default for .json. JSON files can be directly imported.
import pkg from "./package.json";
pkg.name; // => "my-package"
During bundling, the parsed JSON is inlined into the bundle as a JavaScript object.
const pkg = {
  name: "my-package",
  // ... other fields
};

pkg.name;
If a .json file is passed as an entrypoint to the bundler, it is converted to a .js module that export defaults the parsed object.
{
  "name": "John Doe",
  "age": 35,
  "email": "johndoe@example.com"
}

jsonc

JSON with Comments loader. Default for .jsonc. JSONC (JSON with Comments) files can be directly imported. Bun parses them, stripping out comments and trailing commas.
import config from "./config.jsonc";
console.log(config);
During bundling, the parsed JSONC is inlined into the bundle as a JavaScript object, identical to the json loader.
var config = {
  option: "value",
};
Bun automatically uses the jsonc loader for tsconfig.json, jsconfig.json, package.json, and bun.lock files.

toml

TOML loader. Default for .toml. TOML files can be directly imported. Bun parses them with its native TOML parser.
import config from "./bunfig.toml";
config.logLevel; // => "debug"

// with an import attribute:
// import myCustomTOML from './my.config' with {type: "toml"};
During bundling, the parsed TOML is inlined into the bundle as a JavaScript object.
var config = {
  logLevel: "debug",
  // ...other fields
};
config.logLevel;
If a .toml file is passed as an entrypoint, it is converted to a .js module that export defaults the parsed object.
name = "John Doe"
age = 35
email = "johndoe@example.com"

yaml

YAML loader. Default for .yaml and .yml. YAML files can be directly imported. Bun parses them with its native YAML parser.
import config from "./config.yaml";
console.log(config);

// with an import attribute:
import data from "./data.txt" with { type: "yaml" };
During bundling, the parsed YAML is inlined into the bundle as a JavaScript object.
var config = {
  name: "my-app",
  version: "1.0.0",
  // ...other fields
};
If a .yaml or .yml file is passed as an entrypoint, it is converted to a .js module that export defaults the parsed object.
name: John Doe
age: 35
email: johndoe@example.com

text

Text loader. Default for .txt. Text files can be directly imported. The file is read and returned as a string.
import contents from "./file.txt";
console.log(contents); // => "Hello, world!"

// To import an html file as text
// The "type" attribute overrides the default loader.
import html from "./index.html" with { type: "text" };
When referenced during a build, the contents are inlined into the bundle as a string.
var contents = `Hello, world!`;
console.log(contents);
If a .txt file is passed as an entrypoint, it is converted to a .js module that export defaults the file contents.
Hello, world!

napi

Native addon loader. Default for .node. In the runtime, native addons can be directly imported.
import addon from "./addon.node";
console.log(addon);
In the bundler, .node files are handled with the file loader.

sqlite

SQLite loader. Requires with { "type": "sqlite" } import attribute. In the runtime and bundler, SQLite databases can be directly imported. Bun loads the database with bun:sqlite.
import db from "./my.db" with { type: "sqlite" };
The sqlite loader is only supported when the target is bun.
By default, the database file on disk is not bundled into the final output; it stays external to the bundle, so you can use a database loaded elsewhere. You can change this behavior with the "embed" attribute:
// embed the database into the bundle
import db from "./my.db" with { type: "sqlite", embed: "true" };
When using a standalone executable, the database is embedded into the single-file executable.Otherwise, the database to embed is copied into the outdir with a hashed filename.

html

HTML loader. Default for .html. The html loader processes HTML files and bundles any referenced assets. It:
  • Bundles and hashes referenced JavaScript files (<script src="...">)
  • Bundles and hashes referenced CSS files (<link rel="stylesheet" href="...">)
  • Hashes referenced images (<img src="...">)
  • Preserves external URLs (by default, anything starting with http:// or https://)
For example, given this HTML file:
src/index.html
<!DOCTYPE html>
<html>
  <body>
    <img src="./image.jpg" alt="Local image" />
    <img src="https://example.com/image.jpg" alt="External image" />
    <script type="module" src="./script.js"></script>
  </body>
</html>
Bun outputs a new HTML file with the bundled assets:
dist/index.html
<!DOCTYPE html>
<html>
  <body>
    <img src="./image-HASHED.jpg" alt="Local image" />
    <img src="https://example.com/image.jpg" alt="External image" />
    <script type="module" src="./output-ALSO-HASHED.js"></script>
  </body>
</html>
The loader uses lol-html to extract script and link tags as entrypoints, and other assets as external.
The selectors are:
  • audio[src]
  • iframe[src]
  • img[src]
  • img[srcset]
  • link:not([rel~='stylesheet']):not([rel~='modulepreload']):not([rel~='manifest']):not([rel~='icon']):not([rel~='apple-touch-icon'])[href]
  • link[as='font'][href], link[type^='font/'][href]
  • link[as='image'][href]
  • link[as='style'][href]
  • link[as='video'][href], link[as='audio'][href]
  • link[as='worker'][href]
  • link[rel='icon'][href], link[rel='apple-touch-icon'][href]
  • link[rel='manifest'][href]
  • link[rel='stylesheet'][href]
  • script[src]
  • source[src]
  • source[srcset]
  • video[poster]
  • video[src]
HTML Loader Behavior in Different ContextsThe html loader behaves differently depending on how it’s used:
  • Static Build: When you run bun build ./index.html, Bun produces a static site with all assets bundled and hashed.
  • Runtime: When you run bun run server.ts (where server.ts imports an HTML file), Bun bundles assets on the fly during development, enabling features like hot module replacement.
  • Full-stack Build: When you run bun build --target=bun server.ts (where server.ts imports an HTML file), the import resolves to a manifest object that Bun.serve uses to serve pre-bundled assets in production.

css

CSS loader. Default for .css. CSS files can be directly imported. The bundler parses and bundles them, handling @import statements and url() references.
import "./styles.css";
During bundling, all imported CSS files are bundled together into a single .css file in the output directory.
.my-class {
  background: url("./image.png");
}

sh

Bun Shell loader. Default for .sh files. This loader parses Bun Shell scripts. It’s only supported when starting Bun itself, so it’s not available in the bundler or in the runtime.
bun run ./script.sh

file

File loader. Default for all unrecognized file types. The file loader resolves the import as a path/URL to the imported file. It’s commonly used for referencing media or font assets.
// logo.ts
import logo from "./logo.svg";
console.log(logo);
In the runtime, Bun checks that logo.svg exists and resolves the import to its absolute path on disk.
bun run logo.ts
# Output: /path/to/project/logo.svg
In the bundler, the file is copied into outdir as-is, and the import resolves to a relative path pointing to the copied file.
// Output
var logo = "./logo.svg";
console.log(logo);
If publicPath is set, the import uses its value as a prefix to construct an absolute path/URL.
Public pathResolved import
"" (default)/logo.svg
"/assets"/assets/logo.svg
"https://cdn.example.com/"https://cdn.example.com/logo.svg
The location and file name of the copied file are determined by the value of naming.asset.