Skip to content

Latest commit

 

History

History
296 lines (223 loc) · 7.39 KB

File metadata and controls

296 lines (223 loc) · 7.39 KB
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.

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 and passes the complete official 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 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 #
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:

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:

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:

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 Dates 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:

[database]
host = "localhost"
port = 5432
name = "myapp"

[redis]
host = "localhost"
port = 6379

[features]
auth = true
rateLimit = true
analytics = false

Default Import

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:

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:

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:

import myConfig from "./my.config" with { type: "toml" };

CommonJS

You can also require TOML files in CommonJS:

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:

[server]
port = 3000
host = "localhost"

[features]
debug = true
verbose = false
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:

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:

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:

const config = await import("./config.toml");