Skip to main content
Bun uses the file extension to determine which built-in loader to apply. The same set of loaders is used by both the runtime and the bundler. Supported extensions out of the box: .js .jsx .cjs .mjs .mts .cts .ts .tsx .css .json .jsonc .toml .yaml .yml .txt .wasm .node .html

Importing non-JS files

import pkg from "./package.json";      // object
import config from "./bunfig.toml";    // object
import readme from "./readme.txt";     // string
import logo from "./logo.png";         // URL/path string (file loader)
import styles from "./app.module.css"; // CSS Modules object
You can explicitly specify a loader using the type import attribute:
import data from "./myfile" with { type: "toml" };
import html from "./index.html" with { type: "text" }; // override default html loader

Built-in loaders

js — JavaScript

Default for .cjs and .mjs. Parses the file and applies dead-code elimination and tree shaking. Bun does not down-convert syntax.

jsx — JavaScript + JSX

Default for .js and .jsx. Same as js, but JSX syntax is also supported. JSX is transformed to plain JavaScript based on your tsconfig.json compilerOptions.jsx setting.

ts — TypeScript

Default for .ts, .mts, .cts. Strips all TypeScript syntax, then behaves like the js loader. No type checking is performed.

tsx — TypeScript + JSX

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

json — JSON

Default for .json. JSON files can be imported directly and are inlined as JavaScript objects in the bundle.
import pkg from "./package.json";
pkg.name; // => "my-package"
When a .json file is used as a bundler entrypoint, it is converted to a .js module that export defaults the parsed object.

jsonc — JSON with Comments

Default for .jsonc. Strips comments and trailing commas, then behaves like the json loader. Bun automatically uses this loader for tsconfig.json, jsconfig.json, package.json, and bun.lock.

toml — TOML

Default for .toml. Parses the file using Bun’s native TOML parser and inlines the result as a JavaScript object.
import config from "./bunfig.toml";
config.logLevel; // => "debug"

yaml — YAML

Default for .yaml and .yml. Parses the file using Bun’s native YAML parser and inlines the result as a JavaScript object.
import config from "./config.yaml";
config.name; // => "my-app"

text — Plain text

Default for .txt. File contents are read and inlined as a string.
import contents from "./readme.txt";
console.log(contents); // => "Hello, world!"
Override the loader to import any file as text:
import html from "./index.html" with { type: "text" };

css — CSS

Default for .css. CSS files can be imported from JavaScript. The bundler processes @import statements and url() references, and all imported CSS is combined into a single .css file in outdir.
import "./styles.css";
See CSS Bundling for full details including CSS Modules and syntax lowering.

html — HTML

Default for .html. Processes an HTML file and bundles any referenced assets.
  • <script src="..."> — bundled and hashed
  • <link rel="stylesheet" href="..."> — bundled and hashed
  • <img src="..."> — hashed
  • External URLs (http://, https://) — preserved as-is
bun build ./index.html --outdir ./dist
The html loader behaves differently depending on context. With bun build ./index.html it produces a static site. When imported from server code and used with Bun.serve(), it enables the fullstack dev server with HMR. See Fullstack Development for more.

file — File (assets)

Default for all unrecognized extensions. The file is copied to outdir as-is and the import is replaced with the relative path to the copied file.
import logo from "./logo.svg";
console.log(logo); // => "./logo-a7305bdef.svg"
With a publicPath configured:
await Bun.build({
  entrypoints: ["./index.ts"],
  outdir: "./out",
  publicPath: "https://cdn.example.com/",
});
// logo => "https://cdn.example.com/logo-a7305bdef.svg"
The copied file name is determined by naming.asset (default: [name]-[hash].[ext]).

sqlite — SQLite database

Requires with { type: "sqlite" }. Loads the database using bun:sqlite.
import db from "./my.db" with { type: "sqlite" };
db.query("SELECT * FROM users").all();
To embed the database into a standalone executable, add embed: "true":
import db from "./my.db" with { type: "sqlite", embed: "true" };
SQLite imports require --target=bun.

napi — Native addon

Default for .node. Native addons can be imported at runtime:
import addon from "./addon.node";
console.log(addon.hello());
In the bundler, .node files are treated as assets (copied using the file loader).

Custom loaders in Bun.build()

Map additional file extensions to built-in loaders using the loader option:
await Bun.build({
  entrypoints: ["./index.tsx"],
  outdir: "./out",
  loader: {
    ".png": "dataurl",  // Inline as a base64 data URL
    ".txt": "text",     // Inline as a string
    ".svg": "text",     // Treat SVGs as text
    ".yaml": "yaml",    // Already the default, but explicit
  },
});

Loader name reference

LoaderDescription
jsJavaScript (no JSX)
jsxJavaScript + JSX
tsTypeScript
tsxTypeScript + JSX
jsonJSON → inlined object
jsoncJSON with comments → inlined object
tomlTOML → inlined object
yamlYAML → inlined object
textText file → inlined string
cssCSS bundler
htmlHTML bundler
fileAsset — copied to outdir, import becomes path
dataurlAsset — inlined as data: URL
sqliteSQLite database (via bun:sqlite)
napiNative Node addon (.node)
wasmWebAssembly module

Custom loaders via plugins

For file types not covered by built-in loaders, use the plugin API:
import { plugin } from "bun";

plugin({
  name: "svg-loader",
  setup(build) {
    build.onLoad({ filter: /\.svg$/ }, async (args) => {
      const svg = await Bun.file(args.path).text();
      return {
        contents: `export default ${JSON.stringify(svg)}`,
        loader: "js",
      };
    });
  },
});
See Bundler Plugins for full documentation.

Build docs developers (and LLMs) love