Se você já gerenciou um cluster Kubernetes, configurou um workflow do GitHub Actions ou escreveu um arquivo Docker Compose, você já escreveu YAML — provavelmente muito. YAML é o formato de configuração que alimenta a maior parte das ferramentas modernas de DevOps. Mas apesar de estar em todo lugar, é um formato que surpreende as pessoas constantemente. Já depurei mais do que minha cota de erros de indentação YAML às 23h com um deploy bloqueado. Vamos garantir que você não precise passar por isso.
YAML significa YAML Ain't Markup Language — sim, é um acrônimo recursivo. Originalmente era "Yet Another Markup Language", mas foi renomeado para enfatizar que é um formato de serialização de dados, não uma linguagem de marcação de documentos. A especificação YAML 1.2 é o padrão atual, embora muitas ferramentas ainda implementem YAML 1.1, que tem algumas diferenças genuinamente perigosas que abordaremos abaixo.
O Básico: Sintaxe YAML de Relance
YAML usa indentação (apenas espaços — nunca tabulações) para expressar estrutura. Um documento YAML é um mapeamento (pares chave-valor), uma sequência (uma lista) ou um escalar (um único valor). Aqui está uma configuração real no estilo Kubernetes que cobre o essencial:
# This is a comment — YAML supports them, JSON does not
app:
name: payment-service
version: "2.1.0" # quoted to keep it a string
port: 8080
debug: false
timeout: 30.5
tags:
- payments
- backend
- critical
database:
host: postgres.internal
port: 5432
ssl: true
password: null # explicitly no valueSem chaves, sem aspas na maioria das strings, sem vírgulas. Para um arquivo que humanos editam todos os dias, essa clareza se acumula rapidamente. Mas o YAML paga por essa legibilidade com complexidade — há muita coisa acontecendo internamente.
Tipos Escalares: Strings, Números, Booleanos, Null
O YAML infere tipos pela aparência do valor. Isso é conveniente na maioria das vezes e silenciosamente catastrófico em alguns casos específicos.
# Strings — quotes are optional unless value is ambiguous
name: Alice
greeting: "Hello, world"
message: 'single quotes work too'
path: /usr/local/bin # unquoted — still a string
# Numbers
integer: 42
negative: -7
float: 3.14159
scientific: 6.022e23
# Booleans
ssl_enabled: true
verbose: false
# Null
api_key: null
legacy_field: ~ # tilde is also null in YAMLyes, no, on, off, true, false,
y, n, Y, N — e suas variantes maiúsculas —
são todos interpretados como booleanos. Isso significa que o código de país ISO NO (Noruega) se torna
false booleano. O YAML 1.2 corrigiu isso. Sempre use aspas em strings que parecem booleanos. Veja a
entrada da Wikipedia sobre o Problema da Noruega
para a história completa.# YAML 1.1 implicit type coercion — these silently become booleans:
country: NO # → false (Norway Problem!)
enabled: yes # → true
toggle: on # → true
# The fix: always quote when there's any ambiguity
country: "NO"
enabled: "yes"
version: "1.0" # also quote version numbers — 1.0 would be a floatSequências: Listas em YAML
Listas usam um prefixo hífen-espaço. Cada item pode ser um escalar, um mapeamento ou outra sequência:
# Simple list
languages:
- Python
- Go
- TypeScript
# List of objects (common in Kubernetes)
containers:
- name: api
image: my-api:latest
port: 8080
- name: sidecar
image: envoy:v1.28
port: 9901
# Inline flow style (valid YAML, less readable)
tags: [payments, backend, v2]Strings Multilinha: Bloco Literal vs Dobrado
É aqui que o YAML supera o JSON para arquivos de configuração. Dois operadores especiais lidam graciosamente com strings multilinha:
# Literal block scalar (|) — preserves newlines exactly
startup_script: |
#!/bin/bash
set -e
echo "Starting service..."
npm start
# Folded scalar (>) — folds newlines into spaces (good for long descriptions)
description: >
This service handles payment processing
for all regions. It connects to Stripe
and falls back to PayPal.
# Result: "This service handles payment processing for all regions. It connects to Stripe and falls back to PayPal."
# Chomp modifiers
keep_trailing: |+
line one
line two
strip_trailing: |-
line one
line twoO operador | é o que torna os scripts run: multilinha do GitHub Actions
legíveis. A folha de cola yaml-multiline.info
é a forma mais rápida de lembrar qual modificador de chomp faz o quê. Sem esses escalares de bloco, você estaria escrevendo
quebras de linha escapadas em uma única string — o que é o que o JSON te força a fazer.
Tabulações vs Espaços — A Regra Cardinal
.yml e .yaml. Dois espaços é a
convenção quase universal.Esta é a causa número 1 de erros crípticos no YAML. Uma tabulação parece idêntica a espaços na maioria dos editores. Ative "mostrar caracteres de espaço em branco" no seu editor ao depurar YAML, ou cole seu arquivo no Validador YAML para receber uma mensagem de erro clara apontando para a linha exata.
Exemplo Real: Workflow do GitHub Actions
Aqui está um trecho real de workflow do GitHub Actions. Note como o bloco run: multilinha
usa o escalar de bloco literal e como a indentação determina a estrutura:
name: CI
on:
push:
branches: [main, develop]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
- name: Install dependencies
run: npm ci
- name: Run tests
run: |
npm run lint
npm run test -- --coverage
npm run buildExemplo Real: Manifesto de Deployment do Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-api
namespace: production
labels:
app: payment-api
version: "2.1.0"
spec:
replicas: 3
selector:
matchLabels:
app: payment-api
template:
metadata:
labels:
app: payment-api
spec:
containers:
- name: api
image: payment-api:2.1.0
ports:
- containerPort: 8080
env:
- name: NODE_ENV
value: production
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"Analisando YAML em Python e JavaScript
Em Python, a biblioteca PyYAML
é a escolha padrão. Sempre use safe_load(), não load() — a versão insegura
pode executar código Python arbitrário a partir de um arquivo YAML:
import yaml
# Reading a YAML config file
with open('config.yaml', 'r') as f:
config = yaml.safe_load(f)
print(config['app']['name']) # payment-service
print(config['app']['port']) # 8080 (integer, not string)
print(config['app']['tags']) # ['payments', 'backend', 'critical']
# Writing Python data to YAML
data = {
'service': 'auth-api',
'replicas': 2,
'endpoints': ['/login', '/logout', '/refresh']
}
with open('output.yaml', 'w') as f:
yaml.dump(data, f, default_flow_style=False)Em JavaScript/Node.js, js-yaml é a biblioteca mais usada:
import yaml from 'js-yaml';
import fs from 'fs';
// Parse YAML string
const raw = fs.readFileSync('config.yaml', 'utf8');
const config = yaml.load(raw);
console.log(config.app.name); // payment-service
console.log(config.app.tags); // ['payments', 'backend', 'critical']
// Dump an object to YAML string
const output = yaml.dump({
name: 'my-service',
port: 3000,
tags: ['api', 'public']
});
console.log(output);Conclusão
A sintaxe baseada em indentação do YAML, o suporte a comentários e as strings multilinha legíveis o tornam a escolha certa para arquivos de configuração que humanos escrevem e mantêm. Mas ele vem com armadilhas reais: o Problema da Noruega, confusão entre tabulação/espaço e coerção implícita de tipos dos parsers YAML 1.1. Conheça as regras, use aspas em tudo que for ambíguo, configure seu editor para mostrar espaço em branco e use um Formatador YAML para manter os arquivos consistentes. O YAML é uma ferramenta poderosa quando você entende onde ele morde.