toml(npm パッケージ)の使い方 — Node.js で TOML ファイルをパースする
一言でいうと
toml は、TOML 形式の文字列を JavaScript オブジェクトに変換する軽量パーサーです。 TOML v1.1.0 仕様に 99.0% 準拠しており、ランタイム依存ゼロで動作します。
どんな時に使う?
- アプリケーションの設定ファイルを TOML で管理したい時 —
config.tomlを読み込んでオブジェクトとして扱いたいケース - Rust や Go エコシステムのツールが出力する TOML を Node.js で処理したい時 —
Cargo.tomlや Hugo の設定ファイルなどの解析 - JSON や YAML の代替としてより人間に読みやすい設定フォーマットを採用したい時 — コメントが書ける、型が明確、などの TOML の利点を活かしたいケース
インストール
# npm
npm install toml
# yarn
yarn add toml
# pnpm
pnpm add toml
注意: v4.x は Node.js 20 以降が必要です。
基本的な使い方
import { parse } from 'toml';
import { readFileSync } from 'node:fs';
// TOML ファイルを読み込んでパース
const tomlString = readFileSync('./config.toml', 'utf-8');
const config = parse(tomlString);
console.log(config);
config.toml の例:
[server]
host = "0.0.0.0"
port = 8080
[database]
url = "postgres://localhost:5432/myapp"
pool_size = 10
パース結果:
{
server: { host: "0.0.0.0", port: 8080 },
database: { url: "postgres://localhost:5432/myapp", pool_size: 10 }
}
よく使う API・パターン
toml パッケージが公開する API は parse 関数のみですが、実用上よく遭遇するパターンを網羅的に紹介します。
1. parse() — 基本のパース
import { parse } from 'toml';
const data = parse(`
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
`);
console.log(data.title); // "TOML Example"
console.log(data.owner.name); // "Tom Preston-Werner"
2. パースエラーのハンドリング
parse は不正な TOML に対して、line と column プロパティを持つ例外をスローします。
import { parse } from 'toml';
try {
parse(`
[server]
port = "not_a_number
`);
} catch (e: unknown) {
if (e instanceof Error && 'line' in e && 'column' in e) {
const line = (e as any).line;
const column = (e as any).column;
console.error(`Parse error at line ${line}, column ${column}: ${e.message}`);
}
}
3. 日付・時刻の扱い
TOML の日付型は種類によって返却される型が異なります。これは重要なポイントです。
import { parse } from 'toml';
const data = parse(`
odt = 1979-05-27T07:32:00Z # タイムゾーン付き → Date オブジェクト
ldt = 1979-05-27T07:32:00 # ローカル日時 → string
ld = 1979-05-27 # ローカル日付 → string
lt = 07:32:00 # ローカル時刻 → string
`);
// 型に応じた処理の分岐
if (data.odt instanceof Date) {
console.log(data.odt.toISOString()); // "1979-05-27T07:32:00.000Z"
}
console.log(typeof data.ldt); // "string"
console.log(typeof data.ld); // "string"
console.log(typeof data.lt); // "string"
4. 特殊な数値型の扱い
TOML は 16 進数・8 進数・2 進数リテラルや、inf/nan をサポートしています。
import { parse } from 'toml';
const data = parse(`
hex = 0xDEADBEEF
oct = 0o755
bin = 0b11010110
pos_inf = inf
neg_inf = -inf
not_a_number = nan
`);
console.log(data.hex); // 3735928559
console.log(data.oct); // 493
console.log(data.bin); // 214
console.log(data.pos_inf === Infinity); // true
console.log(data.neg_inf === -Infinity); // true
console.log(Number.isNaN(data.not_a_number)); // true
5. ネストされたテーブルと配列テーブル
実際の設定ファイルでよく使われる複雑な構造のパース例です。
import { parse } from 'toml';
const data = parse(`
[servers]
[servers.alpha]
ip = "10.0.0.1"
role = "frontend"
[servers.beta]
ip = "10.0.0.2"
role = "backend"
[[products]]
name = "Hammer"
sku = 738594937
[[products]]
name = "Nail"
sku = 284758393
color = "gray"
`);
// ドットキーによるネストテーブル
console.log(data.servers.alpha.ip); // "10.0.0.1"
// [[products]] は配列として返される
console.log(data.products.length); // 2
console.log(data.products[0].name); // "Hammer"
console.log(data.products[1].color); // "gray"
型安全に使うための Tips
parse の戻り値は Record<string, any> 相当なので、型安全に扱うには自前で型定義を用意します。
import { parse } from 'toml';
import { readFileSync } from 'node:fs';
interface AppConfig {
server: {
host: string;
port: number;
};
database: {
url: string;
pool_size: number;
};
}
function loadConfig(path: string): AppConfig {
const raw = readFileSync(path, 'utf-8');
const parsed = parse(raw) as AppConfig;
// 必要に応じてバリデーションを追加
if (!parsed.server?.host || !parsed.server?.port) {
throw new Error('Invalid config: server section is incomplete');
}
return parsed;
}
const config = loadConfig('./config.toml');
console.log(config.server.port); // 型補完が効く
より厳密なバリデーションが必要な場合は、
zodやvalibotと組み合わせるのがおすすめです。
類似パッケージとの比較
| パッケージ | TOML バージョン | 書き出し(stringify) | 依存 | 特徴 |
|---|---|---|---|---|
| toml (本記事) | v1.1.0 | ❌ なし | 0 | パース専用。軽量・高準拠率 (99.0%) |
| @iarna/toml | v1.0.0 | ✅ あり | 0 | パース+書き出し両対応。更新停止気味 |
| smol-toml | v1.0.0 | ✅ あり | 0 | ESM ネイティブ。ブラウザ対応 |
| @ltd/j-toml | v1.0.0 | ✅ あり | 0 | 高精度(BigInt 対応)。API がやや独特 |
選び方の目安:
- パースだけでいい →
toml(本パッケージ)がシンプルで最適 - TOML の書き出しも必要 →
smol-tomlまたは@iarna/toml - 64bit 整数の精度が必要 →
@ltd/j-toml(BigInt を返せる)
注意点・Tips
1. パース専用であること
toml パッケージは パース(読み込み)のみ をサポートしています。JavaScript オブジェクトを TOML 文字列に変換(stringify)する機能はありません。書き出しが必要な場合は別のパッケージを使ってください。
2. 64bit 整数の精度限界
JavaScript の Number 型は Number.MAX_SAFE_INTEGER(2^53 - 1)を超える整数を正確に表現できません。TOML 仕様では 64bit 整数をサポートしていますが、大きな整数値は精度が失われます。
// この値は正確にパースできない
const data = parse(`big = 9_007_199_254_740_993`); // Number.MAX_SAFE_INTEGER + 2
console.log(data.big === 9007199254740993); // false(精度落ち)
3. ローカル日時は Date ではなく string
前述の通り、タイムゾーン情報のないローカル日時・日付・時刻は 文字列 として返されます。Date オブジェクトを期待してコードを書くとバグの原因になるので注意してください。
4. CommonJS と ESM の両方で使える
// CommonJS
const toml = require('toml');
toml.parse(str);
// ESM
import { parse } from 'toml';
parse(str);
5. ファイル読み込みは自前で行う
toml パッケージはファイル I/O を含みません。fs.readFileSync や fs.readFile で文字列を取得してから parse に渡してください。
// ❌ こういう API はない
// toml.parseFile('./config.toml');
// ✅ 自分でファイルを読む
import { readFileSync } from 'node:fs';
import { parse } from 'toml';
const config = parse(readFileSync('./config.toml', 'utf-8'));
まとめ
toml は TOML v1.1.0 に 99% 準拠した、依存ゼロの軽量パーサーです。API は parse 関数ひとつだけというシンプルさで、設定ファイルの読み込み用途であればこれだけで十分です。書き出し機能が不要なプロジェクトでは、まず第一候補として検討してよいパッケージでしょう。