Każdy projekt potrzebuje konfiguracji, a masz trzy główne opcje: JSON, YAML lub TOML. Używałem wszystkich trzech intensywnie, i każdy doprowadza mnie do szału na różne sposoby. Oto moja szczera ocena, kiedy co stosować.
JSON: Uniwersalny żołnierz
JSON już znasz. Jest wszędzie. Każdy język potrafi go sparsować. Ale bądźmy szczerzy co do jego słabości jako pliku konfiguracyjnego:
- Brak komentarzy. Dosłownie nie możesz wyjaśnić, co robi dane ustawienie. To szaleństwo w pliku konfiguracyjnym.
- Brak przecinka na końcu. Dodaj nową linię na końcu, zapomnij o przecinku w poprzedniej linii — i konfiguracja się sypie.
- Cudzysłowy wszędzie. Każdy klucz wymaga podwójnych cudzysłowów:
{"port": 8080}zamiast po prostuport: 8080.
Mimo tego JSON jest używany do konfiguracji przez npm (package.json), TypeScript (tsconfig.json), VS Code (settings.json) i wiele innych. Powód? Zero niejednoznaczności. JSON jest tak rygorystyczny, że jest tylko jeden sposób jego interpretacji.
YAML: Piękny ale niebezpieczny
YAML wygląda świetnie. Czysty, minimalistyczny, czytelny dla człowieka. Ale ma kilka notorycznych pułapek:
To jest „problem Norwegii", o którym wspomniałem w artykule o YAML. YAML 1.1 traktuje NO, YES, ON, OFF jako wartości boolean. Naprawiono to w YAML 1.2, ale wiele parserów nadal domyślnie używa zachowania z wersji 1.1.
Do tego wrażliwość na wcięcia. Jedna źle umieszczona spacja może kompletnie zmienić znaczenie pliku — a komunikat o błędzie będzie fatalny.
Mimo to YAML jest standardem dla Docker Compose, Kubernetes, GitHub Actions i Ansible. Jeśli pracujesz w obszarze DevOps/cloud, biegłość w YAML jest obowiązkowa.
TOML: Specjalista od konfiguracji
TOML (Tom's Obvious Minimal Language) został zaprojektowany specjalnie do konfiguracji. Jego celem jest bycie oczywistym — czyli (prawie) nie ma sposobu, żeby źle odczytać plik TOML.
Oto jak wygląda konfiguracja TOML:
Co TOML robi naprawdę dobrze: natywne typy daty/czasu (created = 2026-03-08T10:30:00Z), brak problemów z wcięciami, komentarze z # i składnia, którą naprawdę trudno zepsuć.
Wada? Głęboko zagnieżdżone struktury stają się rozwlekłe. TOML jest świetny dla płaskich konfiguracji, ale jeśli potrzebujesz pięciu poziomów zagnieżdżenia, YAML lub JSON mogą być czytelniejsze.
TOML jest używany przez Rust (Cargo.toml), Python (pyproject.toml), Hugo i rosnącą liczbę narzędzi.
Moje rekomendacje
| Scenariusz | Wybór | Dlaczego |
| Konfiguracja generowana maszynowo | JSON | Najbardziej rygorystyczny i kompatybilny |
| DevOps/infrastruktura | YAML | Ekosystem tego wymaga |
| Konfiguracja aplikacji | TOML | Komentarze + minimalna niejednoznaczność |
| Proste ustawienia klucz-wartość | TOML | Najczystszy dla płaskich configów |
| Złożone zagnieżdżone struktury | YAML | Najlepsza składnia zagnieżdżania |
Podsumowanie
Ta sama konfiguracja we wszystkich trzech formatach
Zobaczenie tych samych danych we wszystkich trzech formatach naprawdę uwydatnia różnice. Oto prosta konfiguracja aplikacji:
JSON:
YAML:
TOML:
Zauważ, jak JSON wymaga tych wszystkich cudzysłowów i nawiasów klamrowych, YAML jest najkrótszy, ale opiera się na wcięciach, a TOML stanowi złoty środek z jawnymi nagłówkami sekcji i brakiem zależności od wcięć.
Typowe błędy w plikach konfiguracyjnych
YAML: Przypadkowa konwersja typów. Oprócz problemu Norwegii, YAML zinterpretuje też 3.10 jako liczbę 3.1 (odrzucając końcowe zero) i 1_000 jako 1000. Jeśli Twoje wartości konfiguracyjne to ciągi wersji jak 3.10, zawsze umieszczaj je w cudzysłowach: version: "3.10".
JSON: Zapominanie, że kolejność nie ma znaczenia. Obiekty JSON są nieuporządkowane zgodnie ze specyfikacją. Jeśli Twoje przetwarzanie konfiguracji zależy od kolejności kluczy, budujesz na kruchym fundamencie. Niektóre parsery zachowują kolejność wstawiania, inne nie.
TOML: Zamieszanie z tablicami tabel. TOML używa [[podwójnych.nawiasów]] dla tablic tabel, co sprawia trudności początkującym. Oto jak definiujesz wiele serwerów:
Konfiguracje środowiskowe
Obszar, w którym wszystkie trzy formaty mają trudności, to obsługa nadpisań specyficznych dla środowiska (dev vs staging vs production). Typowe rozwiązania to:
- Wiele plików:
config.base.yaml+config.production.yamlz głębokim łączeniem - Interpolacja zmiennych środowiskowych: Niektóre narzędzia YAML obsługują składnię
${DB_HOST}, ale to nie jest standard - Zewnętrzne narzędzia: Doppler, HashiCorp Vault lub natywne usługi konfiguracyjne w chmurze
Osobiście skłaniam się ku prostemu podejściu: jeden plik konfiguracyjny z rozsądnymi wartościami domyślnymi i zmienne środowiskowe dla wszystkiego, co zmienia się między środowiskami. Wszystkie trzy formaty mogą czytać zmienne środowiskowe na poziomie aplikacji, więc sam format konfiguracji nie musi obsługiwać interpolacji.
Popularność formatów w ekosystemach
| Ekosystem | Główny format | Znane przykłady |
| JavaScript/Node.js | JSON | package.json, tsconfig.json, .eslintrc.json |
| Python | TOML | pyproject.toml, Cargo.toml (Rust) |
| DevOps/Cloud | YAML | docker-compose.yml, manifesty k8s, GitHub Actions |
| Go | TOML/YAML | Oba szeroko stosowane, brak jednego standardu |
| .NET | JSON | appsettings.json (zastąpił web.config oparty na XML) |
Podsumowanie
Nie ma jednej właściwej odpowiedzi. Używaj JSON, gdy potrzebujesz maksymalnej kompatybilności. Używaj YAML, gdy ekosystem tego wymaga (Kubernetes nie zacznie akceptować TOML). Używaj TOML, gdy chcesz komentarze i minimalne niespodzianki.
JSONC i JSON5: JSON z kółkami dostawczymi
Dobra, krytykowaliśmy JSON za brak komentarzy i przecinków na końcu. Ale jest coś, czego nikt ci nie mówi: istnieją warianty JSON, które naprawiają te irytacje, i prawdopodobnie używałeś jednego z nich, nawet o tym nie wiedząc.
Po pierwsze: JSONC (JSON with Comments). Jeśli kiedykolwiek otworzyłeś tsconfig.json i pomyślałeś „zaraz, tu są komentarze... myślałem, że JSON nie pozwala na komentarze?" — tak, to JSONC. To w zasadzie JSON, ale możesz używać komentarzy jednoliniowych // i blokowych /* */. VS Code używa JSONC dla swoich plików settings.json, launch.json i keybindings.json. TypeScriptowy tsconfig.json to technicznie też JSONC, nie ścisły JSON.
Oto jak wygląda JSONC:
Potem jest JSON5, który idzie jeszcze dalej. JSON5 rozluźnia wiele najsurowszych reguł JSON:
- Ciągi w pojedynczych cudzysłowach:
{'name': 'Sarah'}— nareszcie! - Przecinki na końcu:
{"a": 1, "b": 2,}— koniec z szumem w diffach - Klucze bez cudzysłowów (jeśli są poprawnymi identyfikatorami):
{name: "Sarah"} - Liczby szesnastkowe:
0xFF - Wieloliniowe ciągi z kontynuacją ukośnikiem
Infinity,-InfinityiNaNjako poprawne liczby
JSON5 jest świetny dla plików konfiguracyjnych, gdzie ludzie są głównym odbiorcą. Niektóre narzędzia obsługują go natywnie — na przykład .babelrc Babela może być JSON5. Ale nie używaj JSON5 do odpowiedzi API ani wymiany danych. Cały sens ścisłego JSON polega na tym, że wszyscy zgadzają się co do formatu. JSON5 jest dla ludzi, nie dla maszyn.
Moja zasada: jeśli narzędzie obsługuje JSONC lub JSON5, używaj tego. Dosłownie nie ma żadnej wady posiadania komentarzy w plikach konfiguracyjnych. Ale jeśli piszesz bibliotekę czytającą konfiguracje, obsługuj najpierw standardowy JSON, a JSONC/JSON5 jako opcjonalne dodatki.
Kotwice i aliasy YAML: Konfiguracja DRY
Oto prawdziwa zabójcza funkcja YAML, której wielu programistów nigdy nie odkrywa: kotwice i aliasy. Pozwalają zdefiniować blok konfiguracji raz i używać go wszędzie. Zasadniczo DRY (Don't Repeat Yourself) dla plików konfiguracyjnych.
Kotwica jest oznaczona &name, a alias odwołuje się do niej z *name. Oto praktyczny przykład Docker Compose:
Widzisz, co się stało? Zdefiniowaliśmy wspólne ustawienia raz z &common i wciągnęliśmy je do trzech usług za pomocą <<: *common. Bez kotwic kopiowałbyś tę politykę restartu i konfigurację logowania do każdej usługi. A gdy musisz zmienić rotację logów? Jedno miejsce zamiast dwunastu.
Możesz też używać kotwic dla prostszych wartości — nie tylko dla map:
A teraz pułapki. Klucz scalający <<, który czyni kotwice naprawdę potężnymi? Nie jest tak naprawdę częścią specyfikacji YAML 1.2. To było rozszerzenie typów YAML 1.1, i choć większość popularnych parserów nadal go obsługuje, technicznie nie jest standardowy. Więc jeśli używasz ścisłego parsera YAML 1.2, klucze scalające mogą nie działać.
Poza tym kotwice działają tylko w obrębie jednego pliku. Nie możesz odwołać się do kotwicy zdefiniowanej w innym pliku YAML. A komunikaty błędów, gdy pomylisz nazwę aliasu? Zazwyczaj coś w stylu „undefined alias" bez żadnego kontekstu o tym, gdzie miała być kotwica. Klasyczny YAML.
TOML w szczegółach: Zaawansowane funkcje
Większość ludzi zna podstawy TOML — sekcje z [nawiasami], pary klucz-wartość, komentarze z #. Ale TOML ma kilka naprawdę fajnych funkcji, które nie dostają wystarczająco dużo uznania. Pozwól, że je omówię.
Klucze z kropkami pozwalają definiować zagnieżdżone struktury bez nagłówków sekcji:
To przydatne, gdy masz tylko kilka zagnieżdżonych wartości i nie chcesz tworzyć całej sekcji.
Tabele inline dają kompaktową składnię podobną do JSON dla małych obiektów:
Używaj tabel inline oszczędnie — nie mogą zajmować wielu linii i szybko stają się nieczytelne, jeśli wciśniesz w nie za dużo.
Ciągi wieloliniowe występują w dwóch wariantach, i tu TOML jest zaskakująco przemyślany:
Potrójnie cytowany ciąg podstawowy (""") przetwarza sekwencje ucieczki, podczas gdy wersja literalna (''') traktuje wszystko jako surowy tekst. To idealne dla wzorców regex lub ścieżek plików Windows, gdzie nie chcesz, żeby ukośniki wsteczne były interpretowane jako sekwencje ucieczki.
Natywne typy daty/czasu to coś, czego ani JSON, ani YAML nie obsługuje tak czysto:
To są typy pierwszej klasy w TOML, nie ciągi udające daty. Twój parser TOML da ci rzeczywiste obiekty daty/czasu, a nie ciągi, które musisz sam parsować.
Dlaczego Cargo z Rusta wybrało TOML? Bo konfiguracje Cargo to dokładnie idealny przypadek dla TOML: umiarkowanie zagnieżdżone, edytowane przez ludzi, potrzebujące komentarzy i korzystające ze ścisłego typowania. Nie chcesz, żeby wersje Twoich zależności były po cichu interpretowane jako liczby zmiennoprzecinkowe (patrzę na ciebie, YAML).
Bezpieczeństwo
Dobra, to jest sekcja, w której robi się trochę strasznie. Jeśli ładujesz pliki konfiguracyjne z niezaufanych źródeł — albo nawet jeśli myślisz, że tego nie robisz — musisz wiedzieć o atakach deserializacji.
Sztandarowym przykładem jest yaml.load() z PyYAML. W starszych wersjach ta niewinnie wyglądająca funkcja mogła wykonać dowolny kod Pythona osadzony w pliku YAML. Nie żartuję. Spójrz na to:
Jeśli ktoś wrzuci to do konfiguracji YAML i Twoja aplikacja Python załaduje to za pomocą yaml.load() zamiast yaml.safe_load(), dosłownie wykona ten polecenie systemowe. Usunie wszystko. Zainstaluje backdoora. Cokolwiek atakujący chce.
Rozwiązanie jest banalnie proste — zawsze używaj yaml.safe_load() w Pythonie:
Dokumentacja PyYAML teraz przed tym ostrzega, a nowsze wersje pokazują ostrzeżenie o deprecjacji, jeśli użyjesz yaml.load() bez określenia Loadera. Ale wciąż istnieją niezliczone tutoriale i odpowiedzi na Stack Overflow pokazujące niebezpieczną wersję. To mina ukryta na widoku.
Potem jest atak „billion laughs" (znany też jako bomba XML, ale działa też na YAML). Idea polega na rekurencyjnej ekspansji — definiujesz encje, które odwołują się do innych encji, tworząc wykładniczy wzrost:
Każdy poziom mnoży dane przez 5, więc na poziomie 8 lub 9 masz do czynienia z gigabajtami danych z kilku linii YAML. Większość nowoczesnych parserów YAML ma limity głębokości i ekspansji, żeby temu zapobiec, ale warto o tym wiedzieć.
JSON jest z natury bezpieczniejszy, ponieważ nie ma żadnej semantyki wykonawczej. Nie ma sposobu na osadzenie kodu, brak konstruktorów typów, brak ekspansji encji. Parser JSON po prostu czyta dane — ciągi, liczby, wartości boolean, tablice i obiekty. I tyle. To jedna z niedocenianych zalet prostoty JSON. Gdy bezpieczeństwo ma znaczenie, brak funkcji JSON jest w rzeczywistości zaletą.
TOML jest również dość bezpieczny — nie ma możliwości wykonania kodu ani rekurencyjnej ekspansji. Ale jest mniej przetestowany w boju niż parsery JSON, więc utrzymuj swoje biblioteki TOML aktualne.
Podsumowując: jeśli akceptujesz pliki konfiguracyjne od użytkowników lub ze źródeł zewnętrznych, JSON jest najbezpieczniejszym wyborem. Jeśli musisz używać YAML, zawsze stosuj bezpieczne funkcje ładowania i rozważ uruchomienie lintera YAML, żeby wychwycić podejrzane konstrukcje.
Prawdziwe przykłady plików konfiguracyjnych
Teoria jest świetna, ale spójrzmy na prawdziwe pliki konfiguracyjne, które spotkasz w praktyce. Dodałem adnotacje do każdego, żeby podkreślić wzorce specyficzne dla formatu.
Workflow GitHub Actions (YAML):
Tu YAML naprawdę błyszczy. Składnia workflow GitHub Actions byłaby bolesna w JSON — te wszystkie zagnieżdżone listy i struktura oparta na wcięciach naturalnie pasuje do YAML. Widać też, jak komentarze pomagają wyjaśnić strategię macierzową.
Cargo.toml z Rusta (TOML):
Zauważ, jak manifest Cargo używa tabel inline dla zależności z funkcjami. Składnia [[bin]] z podwójnymi nawiasami definiuje tablicę tabel — każdy wpis [[bin]] dodaje kolejny cel binarny. TOML utrzymuje to płaskim i czytelnym bez żadnych gier z wcięciami.
package.json (JSON):
Klasyka. Brak komentarzy, mnóstwo cudzysłowów, ale każde narzędzie na planecie potrafi to odczytać. To, co sprawia, że package.json działa mimo ograniczeń JSON, to fakt, że schemat jest tak dobrze znany — nie potrzebujesz komentarzy, żeby wyjaśnić, co robi scripts.build, bo każdy programista JavaScript już to wie.
.prettierrc (JSON):
Prosta, płaska konfiguracja klucz-wartość. Szczerze, byłoby to trochę ładniejsze jako TOML (komentarze!) lub nawet JSONC, a Prettier obsługuje inne formaty. Ale JSON jest domyślny, i dla czegoś tak prostego nie ma to wielkiego znaczenia.
Migracja między formatami
Więc zdecydowałeś, że format konfiguracji Twojego projektu był błędem i chcesz zmienić. Albo może ściągasz konfigurację z narzędzia używającego innego formatu. Tak czy inaczej, musisz konwertować między TOML, YAML i JSON. Powiem ci, nie zawsze idzie to tak gładko, jak byś chciał.
Narzędzia do konwersji:
- yq — Scyzoryk szwajcarski do YAML. Potrafi konwertować między YAML, JSON, TOML i XML.
yq -o=json config.yamldaje wyjście JSON. To jakjq, ale do YAML. - toml-cli i taplo — Procesory TOML z linii poleceń. Taplo jest szczególnie dobry do formatowania i walidacji TOML.
- Jednoliniowce w Pythonie — W ostateczności
python -c "import yaml, json, sys; print(json.dumps(yaml.safe_load(sys.stdin), indent=2))" < config.yamlkonwertuje YAML na JSON. Nieładne, ale działa. - Konwertery online — Do szybkich jednorazowych konwersji nasze formattery mogą pomóc. Wklej konfigurację do odpowiedniego formattera, oczyść ją i ręcznie przepisz w docelowym formacie.
Kiedy migrować:
- Twój zespół ciągle popełnia błędy wcięć YAML w konfiguracjach CI? Może przejście na TOML zmniejszy te bóle głowy.
- Potrzebujesz komentarzy w pliku konfiguracyjnym JSON? Rozważ migrację do JSONC (jeśli narzędzie to obsługuje) lub TOML.
- Budujesz nowy projekt w Rust/Python i ekosystem oczekuje TOML? Nie walcz z tym — użyj TOML.
Typowe pułapki przy migracji:
Niejawne parsowanie dat w YAML cię ugryzie. Jeśli masz wartość YAML taką jak release: 2024-03-08, YAML interpretuje ją jako obiekt daty, nie ciąg. Skonwertuj to do JSON i możesz dostać "release": "2024-03-08T00:00:00Z" lub "release": "2024-03-08" w zależności od konwertera. Zawsze testuj wyjście.
Ścisłe typowanie TOML oznacza, że nie możesz mieć tablic z mieszanymi typami. W JSON i YAML [1, "two", true] jest całkowicie w porządku. W TOML każdy element tablicy musi być tego samego typu. Jeśli Twoje dane źródłowe mają mieszane tablice, będziesz musiał je przebudować.
I tu jest najważniejsze: komentarze giną. JSON nie obsługuje komentarzy, więc jeśli konwertujesz z TOML lub YAML do JSON, wszystkie Twoje starannie napisane komentarze znikają. W drugą stronę (JSON do YAML/TOML) będziesz chciał ręcznie dodać komentarze, żeby wyjaśnić nieoczywiste ustawienia, bo wersja JSON na pewno ich nie miała.
Jeszcze jedno — kotwice i aliasy YAML nie mają odpowiedników w JSON ani TOML. Jeśli Twoja konfiguracja YAML opiera się na kotwicach dla DRY, konwersja do innego formatu oznacza, że musisz ręcznie zduplikować te wspólne bloki. To może być znaczne zwiększenie rozmiaru pliku dla złożonych konfiguracji.
Wypróbuj sam
Niezależnie od wybranego formatu, utrzymywanie konfiguracji w dobrym formacie ułatwia ich przeglądanie i debugowanie. Nasz TOML Formatter porządkuje niechlujne pliki TOML w mgnieniu oka. YAML Formatter naprawia problemy z wcięciami, zanim spowodują kłopoty. A JSON Formatter sprawia, że nawet głęboko zagnieżdżone konfiguracje JSON są czytelne na pierwszy rzut oka.