# Loaders

> Built-in loaders for the Bun bundler and runtime

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` `.json5` `.toml` `.yaml` `.yml` `.xml` `.txt` `.text` `.md` `.markdown` `.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.

```ts title="index.ts" icon="/icons/typescript.svg"
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, Bun down-converts JSX to plain JavaScript. The exact output depends on the `jsx*` compiler options in your `tsconfig.json`. See the [TypeScript documentation on JSX](https://www.typescriptlang.org/tsconfig#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.

```js
import pkg from "./package.json";
pkg.name; // => "my-package"
```

During bundling, Bun inlines the parsed JSON into the bundle as a JavaScript object.

```js
const pkg = {
  name: "my-package",
  // ... other fields
};

pkg.name;
```

If you pass a `.json` file as an entrypoint to the bundler, Bun converts it to a `.js` module that `export default`s the parsed object.

<CodeGroup>

```json Input
{
  "name": "John Doe",
  "age": 35,
  "email": "johndoe@example.com"
}
```

```js Output
export default {
  name: "John Doe",
  age: 35,
  email: "johndoe@example.com",
};
```

</CodeGroup>

---

### `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.

```js
import config from "./config.jsonc";
console.log(config);
```

During bundling, Bun inlines the parsed JSONC into the bundle as a JavaScript object, identical to the `json` loader.

```js
var config = {
  option: "value",
};
```

<Note>
  Bun automatically uses the `jsonc` loader for `tsconfig.json`, `jsconfig.json`, `package.json`, and `bun.lock` files.
</Note>

---

### `toml`

**TOML loader.** Default for `.toml`.

TOML files can be directly imported. Bun parses them with its native TOML parser.

```js
import config from "./bunfig.toml";
config.logLevel; // => "debug"

// with an import attribute:
// import myCustomTOML from './my.config' with {type: "toml"};
```

During bundling, Bun inlines the parsed TOML into the bundle as a JavaScript object.

```js
var config = {
  logLevel: "debug",
  // ...other fields
};
config.logLevel;
```

If you pass a `.toml` file as an entrypoint, Bun converts it to a `.js` module that `export default`s the parsed object.

<CodeGroup>

```toml Input
name = "John Doe"
age = 35
email = "johndoe@example.com"
```

```js Output
export default {
  name: "John Doe",
  age: 35,
  email: "johndoe@example.com",
};
```

</CodeGroup>

---

### `yaml`

**YAML loader.** Default for `.yaml` and `.yml`.

YAML files can be directly imported. Bun parses them with its native YAML parser.

```js
import config from "./config.yaml";
console.log(config);

// with an import attribute:
import data from "./data.txt" with { type: "yaml" };
```

During bundling, Bun inlines the parsed YAML into the bundle as a JavaScript object.

```js
var config = {
  name: "my-app",
  version: "1.0.0",
  // ...other fields
};
```

If you pass a `.yaml` or `.yml` file as an entrypoint, Bun converts it to a `.js` module that `export default`s the parsed object.

<CodeGroup>

```yaml Input
name: John Doe
age: 35
email: johndoe@example.com
```

```js Output
export default {
  name: "John Doe",
  age: 35,
  email: "johndoe@example.com",
};
```

</CodeGroup>

---

### `xml`

**XML loader.** Default for `.xml`.

XML files can be directly imported. Bun parses them with its native XML 1.0 parser into the compact object shape of [`Bun.XML.parse`](/runtime/xml):

- One key for the root element
- `"@name"` keys for attributes
- Arrays for repeated child elements
- `"#text"` for text next to attributes or children
- Every value is a string

```ts
import doc from "./config.xml";
console.log(doc.config["@version"]);

// via import attribute:
import feed from "./export.rss" with { type: "xml" };
```

During bundling, Bun inlines the parsed XML into the bundle as a JavaScript object.

```ts
var doc = {
  config: {
    "@version": "2",
    // ...other fields
  },
};
```

If you pass a `.xml` file as an entrypoint, Bun converts it to a `.js` module that `export default`s the parsed object.

<CodeGroup>

```xml Input
<user id="1">
  <name>John Doe</name>
  <email>johndoe@example.com</email>
  <role>admin</role>
  <role>editor</role>
</user>
```

```ts Output
export default {
  user: {
    "@id": "1",
    name: "John Doe",
    email: "johndoe@example.com",
    role: ["admin", "editor"],
  },
};
```

</CodeGroup>

---

### `text`

**Text loader.** Default for `.txt` and `.text`.

Text files can be directly imported. Bun reads the file and returns it as a string.

```js
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 the file is referenced during a build, Bun inlines the contents into the bundle as a string.

```js
var contents = `Hello, world!`;
console.log(contents);
```

If you pass a `.txt` file as an entrypoint, Bun converts it to a `.js` module that `export default`s the file contents.

<CodeGroup>

```txt Input
Hello, world!
```

```js Output
export default "Hello, world!";
```

</CodeGroup>

---

### `napi`

**Native addon loader.** Default for `.node`.

In the runtime, native addons can be directly imported.

```js
import addon from "./addon.node";
console.log(addon);
```

<Note>In the bundler, Bun handles `.node` files with the `file` loader.</Note>

---

### `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`.

```js
import db from "./my.db" with { type: "sqlite" };
```

<Warning>The `sqlite` loader is only supported when the target is `bun`.</Warning>

By default, Bun does not bundle the database file on disk into the final output. The database file stays external to the bundle, so you can use a database loaded elsewhere.

You can change this behavior with the `"embed"` attribute:

```js
// embed the database into the bundle
import db from "./my.db" with { type: "sqlite", embed: "true" };
```

<Info>
With a standalone executable, Bun embeds the database into the single-file executable.

Otherwise, the database to embed is copied into the `outdir` with a hashed filename.

</Info>

---

### `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:

```html title="src/index.html" icon="file-code"
<!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:

```html title="dist/index.html" icon="file-code"
<!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`](https://github.com/cloudflare/lol-html) to extract script and link tags as entrypoints, and other assets as external.

<Accordion title="List of supported HTML selectors">
The selectors are:

- `audio[src]`
- `img[src]`
- `img[srcset]`
- `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]`

</Accordion>

<Note>

**HTML Loader Behavior in Different Contexts**

The `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.

</Note>

---

### `css`

**CSS loader.** Default for `.css`.

CSS files can be directly imported. The bundler parses and bundles them, handling `@import` statements and `url()` references.

```js
import "./styles.css";
```

During bundling, Bun combines all imported CSS files into a single `.css` file in the output directory.

```css
.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.

```bash
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.

```js
// 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.

```bash
bun run logo.ts
# Output: /path/to/project/logo.svg
```

In the bundler, Bun copies the file into `outdir` as-is, and the import resolves to a relative path pointing to the copied file.

```js
// 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 path                  | Resolved import                    |
| ---------------------------- | ---------------------------------- |
| `""` (default)               | `./logo.svg`                       |
| `"/assets/"`                 | `/assets/logo.svg`                 |
| `"https://cdn.example.com/"` | `https://cdn.example.com/logo.svg` |

<Note>The value of `naming.asset` determines the location and file name of the copied file.</Note>
