YAMLの基礎
YAMLは、YAML 1.2として標準化された、インデントでスコープを決めるデータ形式です。人が書き、プログラムが読む設定ファイルのために作られました。ネストは波括弧ではなくスペースから生まれ、素のスカラーは推論で型づけされ、コメントは#で始まります。この3つの利便性が、実世界のYAMLバグのほぼすべての原因です。だからこそ、このガイドはルールと落とし穴を一緒に教えます。
YAMLの基礎とは
YAMLは、設定が届くときの形式です。Kubernetesのマニフェスト、GitHub Actionsのワークフロー、docker-composeのファイル、Ansibleのプレイブック――どれもYAMLです。スペースで書かれた入れ子のマップ、ダッシュで書かれたリスト、そしてほとんど姿を見せない括弧。名前はもともとYet Another Markup Languageの略でしたが、作者たちはYAML Ain't Markup Languageと読み替えました――データを記述するのであってドキュメントではない、より正確な読み方です。
現行の標準はYAML 1.2(2009年)です。そして最重要の変更は静かなものでした。1.1は素の単語yes、no、on、offを真偽値として型づけしていましたが、1.2はそうしません。ほとんどのソフトウェアはいまだ既定で1.1のルールを読み込むため、同じ1行のテキストがツールによって別の意味を持ち得ます。YAML 1.2はさらに、ほぼすべてのJSONドキュメントを有効なYAMLにしました――この文法の最もきれいな一文要約です。
このガイドでは、初心者に必要な事柄――インデントのルール、スカラーの型づけ、クォート、ブロックスカラー、アンカー、コメント――を扱い、最後にこのサイトのコンバーターが受け入れ、拒否するものの正確な一覧で締めます。すべてブラウザ内で動き、アップロードは一切ないため、例を貼り付けて安心していじれます。
YAML 1.2はほとんどのJSONドキュメントをそのまま有効なYAMLとして扱います。波括弧の形まで整理できる設定は、すぐにツールの出番です。試しに貼り付けてみましょう――JSONフォーマッターが、整形と検証を行い、すべての構文エラーの正確な行と列を報告してくれます。
まったく新しいファイルで、どちらの形式でも正直に言って成り立つという場面では、JSON vs YAMLの比較がトレードオフを1枚の判断表にまとめ、ドキュメントの種類ごとにどちらの形式が向くかを教えてくれます。
インデントこそが構文
YAMLにおいて、空白文字は飾りではありません――構造そのものです。マッピングは、キー、コロン、スペース、値という並びです。ネストした値は次の行に、さらにインデントを深めて書き、同じインデントの2行は兄弟です。タブはまったく禁じられています。仕様はタブの幅を決められないので、パーサーは推測する代わりにタブを拒否します。エディターはコピーペーストのたびにタブを入り込ませてくる――だからこそ、完璧に見えるのにパースを拒むファイルがあまりに多いのです。
慣習では、1レベルにつきスペース2個です。4個でも6個でも同じく有効です――仕様が禁じているのはタブだけ――しかし2個は、KubernetesとComposeが使い、あらゆるリンターが期待し、深いマニフェストが横にスクロールするのを防ぐ値です。1つのファイルの中で幅を混在させるとインデントエラーが生まれます。2個に決めて、エディターに強制させましょう。
- 1レベル=任意の固定スペース数。慣習は2個。
- インデント内のタブは、変換ではなく拒否される。
- シーケンスの項目は、親キーと同じインデントに置ける――ダッシュが印だから。
- 値はフロースタイルでインラインに書くこともできる:ports: [8080]。
シーケンスを含む入れ子のマッピング
services:
web:
image: nginx:1.27
ports:
- "8080:80"
cache:
image: redis:7パーサーが組み立てるツリー
services ├─ web │ ├─ image: "nginx:1.27" │ └─ ports: ["8080:80"] └─ cache └─ image: "redis:7"
スカラーとノルウェー問題
クォートされた値は常に文字列です。クォートなしの値は推論で型が決まり、YAMLの評判はこの推論から生まれました。素の8080は数値8080になり、空の値はnullになります。これは助けになります――ただし、国コードやバージョン文字列のように、テキストのつもりで書いたものまで推論が型づけするまでは。
古典的な失敗は、ISO国コードのリストでNO――ノルウェー――が真偽値falseとしてパースされることです。これがノルウェー問題。デプロイフラグを黙って無効化するまでは笑い話で済みます。バージョン1.1は、表のとおり、さらに遠くまで行っていました。1.2のコアスキーマはtrueとfalseだけを真偽値として解決し、下の表の残りはプレーンな文字列か十進数の数値として読みます――しかし、あまりに多くのソフトウェアが依然として1.1のルールを適用しているため、防御の習慣としては、文字列であり続けるべきものはすべてクォートすることです。
| 書いたもの | YAML 1.1のパース結果 | YAML 1.2コアスキーマのパース結果 |
|---|---|---|
| no | 真偽値false | 文字列"no" |
| on / off | 真偽値true / false | 文字列"on" / "off" |
| 12:30 | 整数750(六十進法) | 文字列"12:30" |
| 0640 | 整数416(八進法) | 整数640(十進法) |
| 2026-09-19 | 日付オブジェクト | 文字列"2026-09-19" |
| ~ | null | null |
クォートとブロックスカラー
YAMLで文字列を書く方法は3つあります。クォートなしは既定で、ほとんどの値に向いています。シングルクォートはリテラル――エスケープはクォートを重ねる('it''s fine')ことだけです。ダブルクォートは\nや\tのようなバックスラッシュエスケープに対応していて、これはJSONが使うスタイルです。防御のルールもそのまま引き継がれます。構造と誤解されうるもの――コロン、ハッシュ、予約語――が値に含まれるなら、意図的にクォートしてください。
複数行のテキストにはブロックスカラーを使います。|で書くリテラルブロックは、入力したとおりの改行をすべて保持します――シェルスクリプトや証明書に合う形です。>で書くフォールデッドブロックは、行を1つの流れるような段落につなげます――長い説明文に合う形です。どちらもチョンピングインジケーターを取ります。|-は最後の改行を取り除き、|+は末尾の改行をすべて残し、素の|はちょうど1つ残します。
2つのブロックスカラーのスタイル
script: | set -e make build make deploy summary: > Deploys finish in under a minute.
スカラーの解決結果
script: "set -e\nmake build\nmake deploy\n" summary: "Deploys finish in under a minute.\n"
アンカー、エイリアス、再利用
YAMLでは、あるノードに名前を持たせ、他のノードから参照できます。キーの後に&nameと書けば値をアンカーし、別の場所に*nameと書けばエイリアスになります。パーサーはアンカーされたノードのコピーを代わりに差し込みます。1つのリトライポリシーを共有するジョブは、単一の定義を指すだけで済み、変更は1か所で済みます。
この仕組みに乗った拡張が2つあります。マージキー(<<: *nameと書く)は、アンカーされたマッピングのすべてのキーを現在のマッピングに継ぎ接ぎます――ComposeやAnsibleのファイルでよく見られ、1.1時代の慣習で、1.2のコア文法には入らなかったものです。アンカーは悪用もできます。エイリアスの中にエイリアスを入れ子にすれば、10個の定義が100万ノードに膨れ上がります――billion-laughs攻撃――信頼できるパーサーは、ハングアップする代わりに、展開に上限を設け、その上限を報告します。
1つのアンカーと2つのエイリアス
defaults: &base retries: 3 timeout: 30s staging: retries: 3 timeout: 30s log: *base
受け取る側が得るもの
defaults: { retries: 3, timeout: "30s" }
log alias: { retries: 3, timeout: "30s" } (staging.log)コメントと複数ドキュメント
コメントは#で始まり行末まで続きます。クォートされた文字列の中のハッシュはコメントになりません。これは、設計上コメントを排除したJSONに対するYAML最大の人間工学的な勝利であり、人間が保守する設定がYAMLへ流れ込む理由です。ファイルがインラインで自己説明し、レビューでは1行とそのコメントを1つのdiffハンクで引用できるのですから。
1つのファイルに複数のドキュメントを入れることもできます。ダッシュ3つの行で区切ります。先頭の---は任意の開始マーカーで、...がドキュメントの終わりです。これにより、1つの成果物がステージング用設定と本番用設定を並べて運べます。このサイトのコンバーターはすべてのドキュメントをパースし、最後のドキュメントを対象に操作します。一般的なCLIの挙動に合わせたものです。
1つのファイル、2つのドキュメント
env: staging region: eu-1 --- env: production region: us-2
コンバーターが使うもの
env: production region: us-2 (the last document)
このサイトのコンバーターが受け入れるもの
どのYAMLパーサーも、サブセットのパーサーです――1.2の完全な文法は有名なほど大きいため――コンバーターが信頼を得るには、失敗に気づかせて発見させるのではなく、自分のサブセットを明示することです。このサイトのYAMLライブラリは、実際の設定ファイルに現れるブロック構文とフロー構文の上に1.2コアスキーマを実装し、仕様が無制限の作業を許す箇所には意図的な制限を設けています。表がその契約です。
| 機能 | このサイトでの扱い | 動作 |
|---|---|---|
| ブロックのマッピングとシーケンス | 受け入れ | 任意の深さまでネスト可。スペース2個、または一貫した任意のインデント |
| フロースタイル[1, 2]と{a: 1} | 受け入れ | そのまま貼り付けられたJSONドキュメント全体も含む |
| コメントとクォート済みスカラー | 受け入れ | 両方のクォートスタイル、すべてのブロックスカラースタイル |
| インデント内のタブ | 拒否 | 問題の行番号つきで拒否される |
| 明示キー(? key) | 拒否 | JSONに対応物がない――JSONのキーは文字列でなければならない |
| マージキー(<<) | 拒否 | マージは手作業で展開するか、値を直接エイリアスする |
| %YAML 1.1ディレクティブ | 警告 | 1.2コアスキーマを適用。yesとnoは文字列のまま |
| 複数ドキュメント | パース | コンバーターは最後のドキュメントを対象にする |
| エイリアス展開 | 上限つき | 深いエイリアス連鎖は上限で打ち切られ報告される。展開しきることはない |
よくある質問
これらのコンバーターを使うと、YAMLはアップロードされますか?
いいえ。このサイトのすべてのコンバーターは、お使いのブラウザのタブ内でJavaScriptとして動きます。アップロードの段階はなく、受け取るバックエンドもありません。DevToolsで確認できます。Networkパネルを開き、ファイルを変換すると、リクエスト一覧が空のまま変化しないのを見られます。サイトのContent-Security-Policyも、ページスクリプトによる外向きの接続をブロックしています。
正しく見えるのに、ファイルのパースが失敗するのはなぜですか?
犯人はたいてい次の3つのどれかです。インデントに隠れたタブ(パーサーはタブをまったく拒否します)、素のnoやマージキーのような1.1流の書き方(1.2のパーサーは推測しません)、そして推論が意図しない型に変えてしまったクォートなしのスカラーです。良いコンバーターは行を特定して教えてくれます。このサイトのコンバーターもそうです。
YAMLはJSONのスーパーセットですか?
YAML 1.2では、ほぼイエスです。波括弧と角括弧をそのまま残したJSONドキュメントは、変更なしでYAMLとしてパースできます。逆は決して成り立ちません。コメント、アンカー、素のキー、複数行のブロックスカラー、1ファイル内の複数ドキュメントはJSON表現を持たないため、それらを使うファイルにとって、YAMLからJSONへの変換は一方通行の扉です。
ノルウェー問題を避けるには?
型が大事なスカラーは、すべてクォートしてください。素のNOはYAML 1.1のルールでは真偽値falseとしてパースされ、on、off、yes、noもそれに従います。1.2のコアスキーマなら文字列のままですが、多くのデプロイ済みソフトウェアはいまだ1.1を読み込みます。国コード、機能フラグ、バージョン文字列をクォートする――それがコストゼロの習慣です。
アンカーを使うべきですか?それとも値を繰り返すべきですか?
コピーが別々に変わる可能性があるなら、値を繰り返します。本当に1回だけ定義される1つの事実なら、アンカーとエイリアスを使います。アンカーは設定をDRYに保てますが、その場での読みやすさを代償にします――読者は定義まで飛ばなければなりません。マージキーは最も移植性の低い部分です。このサイトのコンバーターを含む多くのパーサーは、継ぎ接ぎの順序を推測する代わりにマージキーを拒否します。
YAMLのインデントはスペース2個?それとも4個?
どちらも有効です――仕様が禁じているのはスペース数ではなくタブ――ですからこれは正しさの問題ではなく慣習の問題です。勝ったのはスペース2個です。KubernetesとComposeが使い、あらゆるリンターが既定にし、深いネストも読みやすく保たれます。大切なのは、1つのファイルの中で幅を混在させないことです。