297 lines
7.4 KiB
Plaintext
297 lines
7.4 KiB
Plaintext
---
|
||
title: TOML
|
||
description: Use Bun's built-in support for TOML files through both runtime APIs and bundler integration
|
||
---
|
||
|
||
In Bun, TOML is a first-class citizen alongside JSON, JSON5, and YAML. You can:
|
||
|
||
- Parse TOML strings with `Bun.TOML.parse`
|
||
- `import` & `require` TOML files as modules at runtime (including hot reloading & watch mode support)
|
||
- `import` & `require` TOML files in frontend apps with Bun's bundler
|
||
|
||
---
|
||
|
||
## Runtime API
|
||
|
||
### `Bun.TOML.parse()`
|
||
|
||
Parse a TOML string into a JavaScript object.
|
||
|
||
```ts
|
||
import { TOML } from "bun";
|
||
const text = `
|
||
name = "my-app"
|
||
version = "1.0.0"
|
||
debug = true
|
||
|
||
[database]
|
||
host = "localhost"
|
||
port = 5432
|
||
|
||
[features]
|
||
tags = ["web", "api"]
|
||
`;
|
||
|
||
const data = TOML.parse(text);
|
||
console.log(data);
|
||
// {
|
||
// name: "my-app",
|
||
// version: "1.0.0",
|
||
// debug: true,
|
||
// database: { host: "localhost", port: 5432 },
|
||
// features: { tags: ["web", "api"] }
|
||
// }
|
||
```
|
||
|
||
#### Supported TOML Features
|
||
|
||
Bun's TOML parser implements the full [TOML v1.1.0 specification](https://github.com/toml-lang/toml/releases/tag/1.1.0) and passes the complete official [toml-test](https://github.com/toml-lang/toml-test) conformance suite.
|
||
|
||
- **Strings**: basic (`"..."`) and literal (`'...'`), including multi-line, with all escapes (`\uHHHH`, `\UHHHHHHHH`, and TOML 1.1's `\xHH` and `\e`)
|
||
- **Integers**: decimal, hex (`0x`), octal (`0o`), and binary (`0b`). Integers outside ±(2^53 - 1) throw, because a JavaScript number cannot represent them losslessly
|
||
- **Floats**: including `inf` and `nan`
|
||
- **Booleans**: `true` and `false`
|
||
- **Date/times**: returned as [Temporal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal) objects — offset date-time as `Temporal.Instant`, local date-time as `Temporal.PlainDateTime`, local date as `Temporal.PlainDate`, and local time as `Temporal.PlainTime`
|
||
- **Arrays**: including mixed types and nested arrays
|
||
- **Tables**: standard (`[table]`) and inline (`{ key = "value" }`), including TOML 1.1 multi-line inline tables
|
||
- **Array of tables**: `[[array]]`
|
||
- **Dotted keys**: `a.b.c = "value"`
|
||
- **Comments**: using `#`
|
||
|
||
```ts
|
||
const data = Bun.TOML.parse(`
|
||
# Application config
|
||
title = "My App"
|
||
|
||
[owner]
|
||
name = "John Doe"
|
||
|
||
[database]
|
||
enabled = true
|
||
ports = [8000, 8001, 8002]
|
||
connection_max = 5000
|
||
|
||
[servers.alpha]
|
||
ip = "10.0.0.1"
|
||
role = "frontend"
|
||
|
||
[servers.beta]
|
||
ip = "10.0.0.2"
|
||
role = "backend"
|
||
`);
|
||
```
|
||
|
||
#### Date/times
|
||
|
||
Each of TOML's four date/time types maps 1:1 onto a Temporal type. Temporal carries nanosecond precision; as the TOML spec permits, fractional seconds beyond nine digits are truncated:
|
||
|
||
```ts
|
||
const doc = Bun.TOML.parse(`
|
||
created = 1979-05-27T00:32:00-07:00 # offset date-time
|
||
meeting = 1979-05-27T07:32:00 # local date-time
|
||
birthday = 1979-05-27 # local date
|
||
opens = 07:32:00 # local time
|
||
`);
|
||
|
||
doc.created; // Temporal.Instant (an offset date-time specifies an instant;
|
||
// the written offset normalizes away: 1979-05-27T07:32:00Z)
|
||
doc.meeting; // Temporal.PlainDateTime
|
||
doc.birthday; // Temporal.PlainDate
|
||
doc.opens; // Temporal.PlainTime
|
||
```
|
||
|
||
#### Error Handling
|
||
|
||
`Bun.TOML.parse()` throws a `SyntaxError` if the TOML is invalid:
|
||
|
||
```ts
|
||
try {
|
||
Bun.TOML.parse("invalid = = =");
|
||
} catch (error) {
|
||
console.error("Failed to parse TOML:", error.message);
|
||
// Failed to parse TOML: TOML Parse error: Expected a value but found '='
|
||
}
|
||
```
|
||
|
||
### `Bun.TOML.stringify()`
|
||
|
||
Serialize a JavaScript object to a TOML document. Scalar keys come first,
|
||
followed by `[table]` and `[[array-of-tables]]` sections:
|
||
|
||
```ts
|
||
Bun.TOML.stringify({
|
||
name: "app",
|
||
server: { host: "localhost", port: 8080 },
|
||
points: [{ x: 1 }, { x: 2 }],
|
||
});
|
||
// name = "app"
|
||
//
|
||
// [server]
|
||
// host = "localhost"
|
||
// port = 8080
|
||
//
|
||
// [[points]]
|
||
// x = 1
|
||
//
|
||
// [[points]]
|
||
// x = 2
|
||
```
|
||
|
||
The top-level value must be an object — a TOML document is a table.
|
||
`Temporal.Instant`, `Temporal.PlainDateTime`, `Temporal.PlainDate`, and
|
||
`Temporal.PlainTime` values become the corresponding TOML date/time
|
||
literals, so `stringify(parse(doc))` round-trips date/time types.
|
||
`Temporal.ZonedDateTime` becomes an offset date-time and `Date` becomes
|
||
an offset date-time in UTC. TOML has no syntax for time-zone or calendar
|
||
annotations, so those are dropped (the ISO fields are written), and its
|
||
years are four digits, so date values outside 0000–9999 and invalid
|
||
`Date`s throw. Because TOML cannot represent them, `null` values,
|
||
`BigInt`, circular structures, `Temporal.PlainYearMonth`,
|
||
`Temporal.PlainMonthDay`, and `Temporal.Duration` also throw; `undefined`,
|
||
function, and symbol properties are skipped (inside arrays they throw,
|
||
since TOML arrays cannot have holes), and passing one of those as the
|
||
top-level value returns `undefined`, as `JSON.stringify` does.
|
||
|
||
---
|
||
|
||
## Module Import
|
||
|
||
### ES Modules
|
||
|
||
Import TOML files directly as ES modules. Bun parses the TOML and exposes it as both default and named exports:
|
||
|
||
```toml config.toml
|
||
[database]
|
||
host = "localhost"
|
||
port = 5432
|
||
name = "myapp"
|
||
|
||
[redis]
|
||
host = "localhost"
|
||
port = 6379
|
||
|
||
[features]
|
||
auth = true
|
||
rateLimit = true
|
||
analytics = false
|
||
```
|
||
|
||
#### Default Import
|
||
|
||
```ts app.ts icon="/icons/typescript.svg"
|
||
import config from "./config.toml";
|
||
|
||
console.log(config.database.host); // "localhost"
|
||
console.log(config.redis.port); // 6379
|
||
```
|
||
|
||
#### Named Imports
|
||
|
||
You can destructure top-level TOML tables as named imports:
|
||
|
||
```ts app.ts icon="/icons/typescript.svg"
|
||
import { database, redis, features } from "./config.toml";
|
||
|
||
console.log(database.host); // "localhost"
|
||
console.log(redis.port); // 6379
|
||
console.log(features.auth); // true
|
||
```
|
||
|
||
Or combine both:
|
||
|
||
```ts app.ts icon="/icons/typescript.svg"
|
||
import config, { database, features } from "./config.toml";
|
||
|
||
// Use the full config object
|
||
console.log(config);
|
||
|
||
// Or use specific parts
|
||
if (features.rateLimit) {
|
||
setupRateLimiting(database);
|
||
}
|
||
```
|
||
|
||
#### Import Attributes
|
||
|
||
Use an import attribute to load any file as TOML:
|
||
|
||
```ts app.ts icon="/icons/typescript.svg"
|
||
import myConfig from "./my.config" with { type: "toml" };
|
||
```
|
||
|
||
### CommonJS
|
||
|
||
You can also `require` TOML files in CommonJS:
|
||
|
||
```ts app.ts icon="/icons/typescript.svg"
|
||
const config = require("./config.toml");
|
||
console.log(config.database.name); // "myapp"
|
||
|
||
// Destructuring also works
|
||
const { database, redis } = require("./config.toml");
|
||
console.log(database.port); // 5432
|
||
```
|
||
|
||
---
|
||
|
||
## Hot Reloading with TOML
|
||
|
||
When you run your application with `bun --hot`, Bun detects changes to TOML files and reloads them without restarting:
|
||
|
||
```toml config.toml
|
||
[server]
|
||
port = 3000
|
||
host = "localhost"
|
||
|
||
[features]
|
||
debug = true
|
||
verbose = false
|
||
```
|
||
|
||
```ts server.ts icon="/icons/typescript.svg"
|
||
import { server, features } from "./config.toml";
|
||
|
||
console.log(`Starting server on ${server.host}:${server.port}`);
|
||
|
||
Bun.serve({
|
||
port: server.port,
|
||
hostname: server.host,
|
||
fetch(req) {
|
||
if (features.verbose) {
|
||
console.log(`${req.method} ${req.url}`);
|
||
}
|
||
return new Response("Hello World");
|
||
},
|
||
});
|
||
```
|
||
|
||
Run with hot reloading:
|
||
|
||
```bash terminal icon="terminal"
|
||
bun --hot server.ts
|
||
```
|
||
|
||
---
|
||
|
||
## Bundler Integration
|
||
|
||
When you bundle with Bun, the bundler parses imported TOML at build time and includes it as a JavaScript module:
|
||
|
||
```bash terminal icon="terminal"
|
||
bun build app.ts --outdir=dist
|
||
```
|
||
|
||
This means:
|
||
|
||
- Zero runtime TOML parsing overhead in production
|
||
- Smaller bundle sizes
|
||
- Tree shaking of unused properties (named imports)
|
||
|
||
### Dynamic Imports
|
||
|
||
You can also dynamically import TOML files:
|
||
|
||
```ts
|
||
const config = await import("./config.toml");
|
||
```
|