toml の使い方

TOML parser for Node.js (TOML v1.1.0 compliant)

v4.1.1/週MITユーティリティ
AI生成コンテンツ

この記事はAIによって生成されました。内容の正確性は保証されません。最新の情報は公式ドキュメントをご確認ください。

toml(npm パッケージ)の使い方 — Node.js で TOML ファイルをパースする

一言でいうと

toml は、TOML 形式の文字列を JavaScript オブジェクトに変換する軽量パーサーです。 TOML v1.1.0 仕様に 99.0% 準拠しており、ランタイム依存ゼロで動作します。

どんな時に使う?

  1. アプリケーションの設定ファイルを TOML で管理したい時config.toml を読み込んでオブジェクトとして扱いたいケース
  2. Rust や Go エコシステムのツールが出力する TOML を Node.js で処理したい時Cargo.toml や Hugo の設定ファイルなどの解析
  3. 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 に対して、linecolumn プロパティを持つ例外をスローします。

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); // 型補完が効く

より厳密なバリデーションが必要な場合は、zodvalibot と組み合わせるのがおすすめです。

類似パッケージとの比較

パッケージTOML バージョン書き出し(stringify)依存特徴
toml (本記事)v1.1.0❌ なし0パース専用。軽量・高準拠率 (99.0%)
@iarna/tomlv1.0.0✅ あり0パース+書き出し両対応。更新停止気味
smol-tomlv1.0.0✅ あり0ESM ネイティブ。ブラウザ対応
@ltd/j-tomlv1.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.readFileSyncfs.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 関数ひとつだけというシンプルさで、設定ファイルの読み込み用途であればこれだけで十分です。書き出し機能が不要なプロジェクトでは、まず第一候補として検討してよいパッケージでしょう。