Complete Configuration File Formats Complete Guide | JSON
이 글의 핵심
Characteristics and differences of frequently used file formats in programming including JSON, YAML, XML, TOML, INI, Markdown. Complete understanding with pros/cons, use cases, parsing methods, and practical examples.
Introduction: The Importance of Configuration File Formats
Every programming project uses configuration files. package.json, docker-compose.yml, nginx.conf, README.md - each format has different characteristics and purposes. Choosing the right format greatly improves code readability and maintainability.
Formats covered in this article:
- JSON (JavaScript Object Notation)
- YAML (YAML Ain’t Markup Language)
- XML (eXtensible Markup Language)
- TOML (Tom’s Obvious, Minimal Language)
- INI (Initialization File)
- Markdown
- Others (Properties, HCL, Jsonnet)
What’s particularly memorable are the trial and errors from my first project. I did it as the book taught, but couldn’t figure out why it didn’t work for days. Eventually, I found the problem through a senior developer’s code review, and learned a lot in the process. This article covers not only theory but also pitfalls you might encounter in practice and their solutions.
Table of Contents
- JSON
- YAML
- XML
- TOML
- INI
- Markdown
- Format Comparison and Selection Guide
- Practical Conversion and Validation
1. JSON (JavaScript Object Notation)
What is JSON?
JSON is a lightweight data interchange format based on JavaScript object notation. It’s easy for humans to read and easy for machines to parse.
JSON Basic Syntax
{
"name": "John Doe",
"age": 30,
"email": "john@example.com",
"isActive": true,
"balance": 1234.56,
"tags": ["developer", "designer"],
"address": {
"street": "123 Main St",
"city": "Seoul",
"zipCode": "12345"
},
"projects": [
{
"id": 1,
"name": "Project A",
"status": "active"
},
{
"id": 2,
"name": "Project B",
"status": "completed"
}
],
"metadata": null
}
JSON Data Types
{
"string": "Hello, World!",
"number": 42,
"float": 3.14159,
"boolean": true,
"null": null,
"array": [1, 2, 3, "mixed", true],
"object": {
"nested": "value"
}
}
JSON Pros and Cons
flowchart TB
JSON[JSON]
subgraph Pros[Advantages]
P1[✅ Fast parsing]
P2[✅ JavaScript native]
P3[✅ Concise syntax]
P4[✅ Widely supported]
end
subgraph Cons[Disadvantages]
C1[❌ No comments]
C2[❌ No trailing commas]
C3[❌ Inconvenient multiline strings]
C4[❌ No date type]
end
JSON --> Pros
JSON --> Cons
JSON Usage Examples
// JavaScript
const config = {
apiUrl: "https://api.example.com",
timeout: 5000,
retries: 3
};
// Convert to JSON
const json = JSON.stringify(config, null, 2);
console.log(json);
// Parse JSON
const parsed = JSON.parse(json);
console.log(parsed.apiUrl);
# Python
import json
config = {
"apiUrl": "https://api.example.com",
"timeout": 5000,
"retries": 3
}
# Convert to JSON
json_str = json.dumps(config, indent=2)
print(json_str)
# Parse JSON
parsed = json.loads(json_str)
print(parsed['apiUrl'])
# File I/O
with open('config.json', 'w') as f:
json.dump(config, f, indent=2)
with open('config.json', 'r') as f:
loaded = json.load(f)
JSON Schema (Validation)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"age": {
"type": "integer",
"minimum": 0,
"maximum": 150
},
"email": {
"type": "string",
"format": "email"
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1
}
},
"required": ["name", "email"]
}
2. YAML (YAML Ain’t Markup Language)
What is YAML?
YAML is a human-readable data serialization format. It expresses hierarchy through indentation and supports comments.
YAML Basic Syntax
# Comments start with #
# Key-value pairs
name: John Doe
age: 30
email: john@example.com
# Boolean
isActive: true
isDeleted: false
# Null
metadata: null
# or
metadata: ~
# Strings (quotes optional)
city: Seoul
country: "South Korea"
description: 'Single quotes.. Complete Configuration File Formats Complete Guide에 대한 완전한 가이드입니다. 실전 예제와 함께 핵심 개념부터 고급 활용까지 다룹니다.' # Multiline strings
bio: |
This is a multi-line string.
It preserves line breaks.
Very useful for long text.
summary: >
This is a folded string.
Line breaks are converted to spaces.
Useful for long paragraphs.
# Arrays (lists)
tags:
- developer
- designer
- writer
# Or inline
tags: ["developer", "designer", "writer"]
# Objects (dictionaries)
address:
street: 123 Main St
city: Seoul
zipCode: "12345"
# Or inline
address: {street: 123 Main St, city: Seoul, zipCode: "12345"}
# Arrays + Objects
projects:
- id: 1
name: Project A
status: active
- id: 2
name: Project B
status: completed
# Anchors and aliases (reuse)
defaults: &defaults
timeout: 30
retries: 3
production:
<<: *defaults
apiUrl: https://api.example.com
development:
<<: *defaults
apiUrl: http://localhost:3000
YAML Cautions
# ❌ No tabs (spaces only)
name: value
nested: error # Error if indented with tabs!
# ✅ Use spaces
name: value
nested: correct
# ❌ Inconsistent indentation
items:
- name: item1
value: 100
- name: item2 # Indentation error!
# ✅ Consistent indentation
items:
- name: item1
value: 100
- name: item2
value: 200
# Special character caution
# Strings with colons (:) need quotes
url: "https://example.com" # Quotes recommended
time: "12:30" # Quotes required
# Strings starting with numbers
version: "1.0" # Quotes needed (otherwise parsed as number)
YAML Usage Examples
# Python
import yaml
config = {
'name': 'MyApp',
'version': '1.0.0',
'database': {
'host': 'localhost',
'port': 5432,
'name': 'mydb'
},
'features': ['auth', 'api', 'admin']
}
# Convert to YAML
yaml_str = yaml.dump(config, default_flow_style=False)
print(yaml_str)
# Parse YAML
parsed = yaml.safe_load(yaml_str)
print(parsed['database']['host'])
# File I/O
with open('config.yaml', 'w') as f:
yaml.dump(config, f, default_flow_style=False)
with open('config.yaml', 'r') as f:
loaded = yaml.safe_load(f)
Docker Compose Example
version: '3.8'
services:
web:
image: nginx:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./html:/usr/share/nginx/html:ro
- ./nginx.conf:/etc/nginx/nginx.conf:ro
environment:
- NGINX_HOST=example.com
- NGINX_PORT=80
depends_on:
- app
networks:
- webnet
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
app:
build:
context: .
dockerfile: Dockerfile
args:
- NODE_ENV=production
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/mydb
- REDIS_URL=redis://redis:6379
volumes:
- ./app:/app
- /app/node_modules
networks:
- webnet
deploy:
replicas: 3
resources:
limits:
cpus: '0.5'
memory: 512M
db:
image: postgres:15
environment:
POSTGRES_DB: mydb
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
volumes:
- db-data:/var/lib/postgresql/data
networks:
- webnet
networks:
webnet:
driver: bridge
volumes:
db-data:
3. XML (eXtensible Markup Language)
What is XML?
XML is an extensible markup language that structures data based on tags. It supports strict syntax and schema validation.
XML Basic Syntax
<?xml version="1.0" encoding="UTF-8"?>
<!-- Comment -->
<configuration>
<!-- Simple elements -->
<name>MyApp</name>
<version>1.0.0</version>
<!-- Attributes -->
<database type="postgresql" ssl="true">
<host>localhost</host>
<port>5432</port>
<name>mydb</name>
<credentials>
<username>user</username>
<password>pass</password>
</credentials>
</database>
<!-- Arrays (repeated elements) -->
<features>
<feature name="auth" enabled="true"/>
<feature name="api" enabled="true"/>
<feature name="admin" enabled="false"/>
</features>
<!-- CDATA (includes special characters) -->
<description><![CDATA[
This is a <description> with special characters: & < > " '
]]></description>
<!-- Namespaces -->
<config xmlns="http://example.com/config"
xmlns:db="http://example.com/database">
<db:connection>localhost</db:connection>
</config>
</configuration>
XML Parsing
# Python (ElementTree)
import xml.etree.ElementTree as ET
# Parse XML
tree = ET.parse('config.xml')
root = tree.getroot()
# Access elements
name = root.find('name').text
print(f"Name: {name}")
# Access attributes
db = root.find('database')
db_type = db.get('type')
print(f"Database type: {db_type}")
# Repeated elements
for feature in root.findall('.//feature'):
name = feature.get('name')
enabled = feature.get('enabled')
print(f"Feature {name}: {enabled}")
# Using XPath
host = root.find('.//database/host').text
print(f"Database host: {host}")
// JavaScript (Browser)
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlString, "text/xml");
// Access elements
const name = xmlDoc.getElementsByTagName("name")[0].textContent;
console.log(name);
// Access attributes
const db = xmlDoc.getElementsByTagName("database")[0];
const dbType = db.getAttribute("type");
console.log(dbType);
XML Schema (XSD)
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="configuration">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="version" type="xs:string"/>
<xs:element name="database" type="DatabaseType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="DatabaseType">
<xs:sequence>
<xs:element name="host" type="xs:string"/>
<xs:element name="port" type="xs:integer"/>
</xs:sequence>
<xs:attribute name="type" type="xs:string" use="required"/>
</xs:complexType>
</xs:schema>
XML Use Cases
<!-- Maven (pom.xml) -->
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>myapp</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.2.0</version>
</dependency>
</dependencies>
</project>
<!-- Spring (applicationContext.xml) -->
<beans xmlns="http://www.springframework.org/schema/beans">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="org.postgresql.Driver"/>
<property name="url" value="jdbc:postgresql://localhost:5432/mydb"/>
</bean>
</beans>
<!-- Android (AndroidManifest.xml) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<uses-permission android:name="android.permission.INTERNET"/>
<application android:label="MyApp">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
</activity>
</application>
</manifest>
4. TOML (Tom’s Obvious, Minimal Language)
What is TOML?
TOML is an easy-to-read and clear configuration file format. It’s an improved version of INI, supporting types and nesting.
TOML Basic Syntax
# Comment
# Key-value pairs
name = "MyApp"
version = "1.0.0"
# Numbers
port = 8080
timeout = 30.5
# Boolean
debug = true
production = false
# Date/time
created_at = 2026-04-01T10:00:00Z
# Arrays
tags = ["rust", "web", "api"]
# Inline tables
author = { name = "John Doe", email = "john@example.com" }
# Tables (sections)
[database]
host = "localhost"
port = 5432
name = "mydb"
[database.credentials]
username = "user"
password = "pass"
# Array of tables
[[servers]]
name = "server1"
ip = "192.168.1.1"
role = "primary"
[[servers]]
name = "server2"
ip = "192.168.1.2"
role = "backup"
# Nested structure
[app.cache]
enabled = true
ttl = 3600
[app.cache.redis]
host = "localhost"
port = 6379
TOML Parsing
# Python
import tomli # Python 3.11+ has built-in tomllib
with open('config.toml', 'rb') as f:
config = tomli.load(f)
print(config['name'])
print(config['database']['host'])
print(config['servers'][0]['name'])
# Generate TOML
import tomli_w
data = {
'name': 'MyApp',
'version': '1.0.0',
'database': {
'host': 'localhost',
'port': 5432
}
}
with open('output.toml', 'wb') as f:
tomli_w.dump(data, f)
// Rust
use serde::Deserialize;
use std::fs;
#[derive(Deserialize)]
struct Config {
name: String,
version: String,
database: Database,
}
#[derive(Deserialize)]
struct Database {
host: String,
port: u16,
}
fn main() {
let contents = fs::read_to_string("config.toml").unwrap();
let config: Config = toml::from_str(&contents).unwrap();
println!("Name: {}", config.name);
println!("DB Host: {}", config.database.host);
}
TOML Use Cases
# Cargo.toml (Rust)
[package]
name = "myapp"
version = "0.1.0"
edition = "2021"
[dependencies]
tokio = { version = "1.35", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
[dev-dependencies]
criterion = "0.5"
[profile.release]
opt-level = 3
lto = true
# pyproject.toml (Python)
[project]
name = "myapp"
version = "1.0.0"
description = "My Python application"
authors = [{name = "John Doe", email = "john@example.com"}]
dependencies = [
"fastapi>=0.104.0",
"uvicorn>=0.24.0",
]
[project.optional-dependencies]
dev = ["pytest>=7.4.0", "black>=23.0.0"]
[tool.black]
line-length = 88
target-version = ['py311']
5. INI (Initialization File)
What is INI?
INI is a simple configuration file format widely used in Windows. It consists of sections and key-value pairs.
INI Basic Syntax
; Comments start with semicolon
# Or hash (#) is also possible
; Global settings (no section)
app_name = MyApp
version = 1.0.0
; Section
[database]
host = localhost
port = 5432
name = mydb
username = user
password = pass
[cache]
enabled = true
ttl = 3600
type = redis
[cache.redis]
host = localhost
port = 6379
; Arrays (non-standard, varies by implementation)
[features]
feature1 = auth
feature2 = api
feature3 = admin
; Or
features = auth,api,admin
INI Parsing
# Python
import configparser
config = configparser.ConfigParser()
config.read('config.ini')
# Read values
app_name = config['DEFAULT']['app_name']
db_host = config['database']['host']
db_port = config.getint('database', 'port')
cache_enabled = config.getboolean('cache', 'enabled')
print(f"App: {app_name}")
print(f"DB: {db_host}:{db_port}")
print(f"Cache: {cache_enabled}")
# Write values
config['database']['host'] = 'db.example.com'
with open('config.ini', 'w') as f:
config.write(f)
INI Use Cases
; php.ini
[PHP]
engine = On
short_open_tag = Off
precision = 14
output_buffering = 4096
zlib.output_compression = Off
implicit_flush = Off
serialize_precision = -1
disable_functions = exec,passthru,shell_exec,system
[Date]
date.timezone = Asia/Seoul
[Session]
session.save_handler = files
session.save_path = "/var/lib/php/sessions"
session.gc_maxlifetime = 1440
; .gitconfig
[user]
name = John Doe
email = john@example.com
[core]
editor = vim
autocrlf = input
[alias]
st = status
co = checkout
br = branch
ci = commit
6. Markdown
What is Markdown?
Markdown is a lightweight markup language for writing formatted documents in plain text.
Markdown Basic Syntax
# Heading 1 (H1)
## Heading 2 (H2)
### Heading 3 (H3)
**Bold** or __Bold__
*Italic* or _Italic_
~~Strikethrough~~
`Inline code`
> Blockquote
> Multiple lines possible
- Unordered list
- Item 2
- Nested item
- Nested item 2
1. Ordered list
2. Item 2
3. Item 3
[Link text](https://example.com)

---
Horizontal rule
| Column 1 | Column 2 | Column 3 |
|----------|----------|----------|
| Value 1 | Value 2 | Value 3 |
| Value 4 | Value 5 | Value 6 |
```code block```
Multiple lines of code
```python
# Language specification (syntax highlighting)
def hello():
print("Hello, World!")
- Checkbox (incomplete)
- Checkbox (complete)
### GitHub Flavored Markdown (GFM)
```markdown
# GitHub Extensions
## Task Lists
- [x] Completed task
- [ ] Incomplete task
- [ ] In progress
## Table Alignment
| Left | Center | Right |
|:-----|:------:|------:|
| Left | Center | Right |
## Emoji
:smile: :rocket: :tada:
## Mentions
@username
## Issue References
#123
## Code Block with Filename
```javascript:app.js
console.log("Hello");
Collapsible Sections
Click to expand
Hidden content$E = mc^2$ $$ \frac{-b \pm \sqrt{b^2 - 4ac}}{2a} $$
### Markdown Parsing
```python
# Python (markdown library)
import markdown
md_text = """
# Hello
This is **bold** and *italic*.
- Item 1
- Item 2
"""
html = markdown.markdown(md_text)
print(html)
# <h1>Hello</h1>
# <p>This is <strong>bold</strong> and <em>italic</em>.</p>
# <ul>
# <li>Item 1</li>
# <li>Item 2</li>
# </ul>
# Using extensions
html = markdown.markdown(md_text, extensions=['tables', 'fenced_code', 'toc'])
// JavaScript (marked library)
import { marked } from 'marked';
const mdText = `
# Hello
This is **bold** text.
`;
const html = marked.parse(mdText);
console.log(html);
7. Format Comparison and Selection Guide
Same Data Representation
JSON
{
"app": {
"name": "MyApp",
"version": "1.0.0",
"features": ["auth", "api"]
},
"database": {
"host": "localhost",
"port": 5432
}
}
YAML
# Example
app:
name: MyApp
version: 1.0.0
features:
- auth
- api
database:
host: localhost
port: 5432
XML
<?xml version="1.0"?>
<config>
<app>
<name>MyApp</name>
<version>1.0.0</version>
<features>
<feature>auth</feature>
<feature>api</feature>
</features>
</app>
<database>
<host>localhost</host>
<port>5432</port>
</database>
</config>
TOML
# Example
[app]
name = "MyApp"
version = "1.0.0"
features = ["auth", "api"]
[database]
host = "localhost"
port = 5432
INI
[app]
name = MyApp
version = 1.0.0
features = auth,api
[database]
host = localhost
port = 5432
Comparison Table
| Feature | JSON | YAML | XML | TOML | INI | Markdown |
|---|---|---|---|---|---|---|
| Readability | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Parsing Speed | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| Comments | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Type Safety | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ | N/A |
| Nested Structure | ✅ | ✅ | ✅ | ✅ | Limited | ✅ |
| File Size | Small | Medium | Large | Medium | Small | Medium |
| Schema Validation | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
Recommendations by Use Case
flowchart TD
Start[Choose File Format] --> Q1{Purpose?}
Q1 -->|API Response| JSON["✅ JSON\nFast parsing"]
Q1 -->|Config File| Q2{Complexity?}
Q1 -->|Documentation| Markdown["✅ Markdown\nREADME, blog"]
Q1 -->|Build Config| Q3{Language?}
Q2 -->|Simple| INI["✅ INI\nSimple config"]
Q2 -->|Medium| TOML["✅ TOML\nRust, Python"]
Q2 -->|Complex| YAML["✅ YAML\nDocker, K8s"]
Q3 -->|Java| XML["✅ XML\nMaven, Spring"]
Q3 -->|JavaScript| JSON["✅ JSON\npackage.json"]
Q3 -->|Rust| TOML["✅ TOML\nCargo.toml"]
Q3 -->|Python| TOML2["✅ TOML\npyproject.toml"]
Project Usage
| Project | Format | Filename |
|---|---|---|
| Node.js | JSON | package.json |
| Python | TOML | pyproject.toml |
| Rust | TOML | Cargo.toml |
| Go | Go | go.mod |
| Docker | YAML | docker-compose.yml |
| Kubernetes | YAML | deployment.yaml |
| Ansible | YAML | playbook.yml |
| Maven | XML | pom.xml |
| Gradle | Groovy | build.gradle |
| Nginx | Custom | nginx.conf |
| Apache | Custom | httpd.conf |
8. Practical Conversion and Validation
Format Conversion
#!/usr/bin/env python3
"""
Configuration file format conversion tool
"""
import json
import yaml
import tomli
import tomli_w
import xml.etree.ElementTree as ET
from pathlib import Path
class ConfigConverter:
@staticmethod
def json_to_yaml(json_file, yaml_file):
"""JSON → YAML"""
with open(json_file, 'r') as f:
data = json.load(f)
with open(yaml_file, 'w') as f:
yaml.dump(data, f, default_flow_style=False, allow_unicode=True)
print(f"✅ Converted: {json_file} → {yaml_file}")
@staticmethod
def yaml_to_json(yaml_file, json_file):
"""YAML → JSON"""
with open(yaml_file, 'r') as f:
data = yaml.safe_load(f)
with open(json_file, 'w') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
print(f"✅ Converted: {yaml_file} → {json_file}")
@staticmethod
def json_to_toml(json_file, toml_file):
"""JSON → TOML"""
with open(json_file, 'r') as f:
data = json.load(f)
with open(toml_file, 'wb') as f:
tomli_w.dump(data, f)
print(f"✅ Converted: {json_file} → {toml_file}")
@staticmethod
def toml_to_json(toml_file, json_file):
"""TOML → JSON"""
with open(toml_file, 'rb') as f:
data = tomli.load(f)
with open(json_file, 'w') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
print(f"✅ Converted: {toml_file} → {json_file}")
# Usage
converter = ConfigConverter()
converter.json_to_yaml('config.json', 'config.yaml')
converter.yaml_to_json('config.yaml', 'config.json')
converter.json_to_toml('config.json', 'config.toml')
Validation Tools
# JSON validation
jq . config.json
# or
python -m json.tool config.json
# YAML validation
yamllint config.yaml
# YAML → JSON (yq)
yq eval -o=json config.yaml
# XML validation
xmllint --noout config.xml
# TOML validation (Python)
python -c "import tomli; tomli.load(open('config.toml', 'rb'))"
Online Tools
# jq (JSON query)
cat config.json | jq '.database.host'
# "localhost"
# Array filtering
cat config.json | jq '.servers[] | select(.role == "primary")'
# Conversion
cat config.json | jq '.database'
# yq (YAML query)
cat config.yaml | yq '.database.host'
# xmllint (XML query)
xmllint --xpath '//database/host/text()' config.xml
Other Formats
Properties (Java)
# application.properties (Spring Boot)
server.port=8080
server.address=0.0.0.0
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=user
spring.datasource.password=pass
# Arrays
spring.profiles.active=dev,debug
# Multiline (backslash)
app.description=This is a very long \
description that spans \
multiple lines.
HCL (HashiCorp Configuration Language)
# Terraform
variable "region" {
description = "AWS region"
type = string
default = "us-west-2"
}
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Name = "WebServer"
Environment = "production"
}
}
output "instance_ip" {
value = aws_instance.web.public_ip
}
Jsonnet (JSON Template)
// config.jsonnet
local env = std.extVar('env');
local base = {
name: 'MyApp',
version: '1.0.0',
};
local envConfig = {
dev: {
apiUrl: 'http://localhost:3000',
debug: true,
},
prod: {
apiUrl: 'https://api.example.com',
debug: false,
},
};
base + envConfig[env]
# Execute
jsonnet -V env=dev config.jsonnet
# {
# "name": "MyApp",
# "version": "1.0.0",
# "apiUrl": "http://localhost:3000",
# "debug": true
# }
ENV Files
# .env
NODE_ENV=production
PORT=3000
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
REDIS_URL=redis://localhost:6379
API_KEY=secret-key-123
DEBUG=false
# Arrays (non-standard)
ALLOWED_HOSTS=localhost,example.com,*.example.com
# Python (python-dotenv)
from dotenv import load_dotenv
import os
load_dotenv()
port = int(os.getenv('PORT', 3000))
database_url = os.getenv('DATABASE_URL')
debug = os.getenv('DEBUG', 'false').lower() == 'true'
print(f"Port: {port}")
print(f"Database: {database_url}")
print(f"Debug: {debug}")
Practical Tips
1. Comments
// JSON doesn't support comments → Use JSON5
// package.json5
{
// Project info
name: "myapp",
version: "1.0.0",
// Dependencies
dependencies: {
express: "^4.18.0", // Trailing commas allowed
},
}
// Or use _comment key (non-standard)
{
"_comment": "This is a comment",
"name": "myapp"
}
2. Environment-specific Configuration
# config.yaml
default: &default
timeout: 30
retries: 3
development:
<<: *default
apiUrl: http://localhost:3000
debug: true
production:
<<: *default
apiUrl: https://api.example.com
debug: false
# Load by environment with Python
import yaml
import os
env = os.getenv('ENV', 'development')
with open('config.yaml') as f:
config = yaml.safe_load(f)
app_config = config[env]
print(app_config)
3. Sensitive Information Management
# config.yaml (exclude sensitive info)
database:
host: localhost
port: 5432
name: mydb
# username and password from environment variables
# .env (exclude from version control)
DB_USERNAME=user
DB_PASSWORD=secret
# .gitignore
.env
*.secret.yaml
# Merge with Python
import yaml
import os
with open('config.yaml') as f:
config = yaml.safe_load(f)
# Override with environment variables
config['database']['username'] = os.getenv('DB_USERNAME')
config['database']['password'] = os.getenv('DB_PASSWORD')
4. Schema Validation
# JSON Schema validation
import json
import jsonschema
schema = {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer", "minimum": 0}
},
"required": ["name"]
}
data = {"name": "John", "age": 30}
try:
jsonschema.validate(data, schema)
print("✅ Valid")
except jsonschema.ValidationError as e:
print(f"❌ Invalid: {e.message}")
Summary
Format Selection Flowchart
flowchart TD
Start[Choose Config File Format] --> Q1{Need comments?}
Q1 -->|No| Q2{Parsing speed important?}
Q1 -->|Yes| Q3{Complexity?}
Q2 -->|Yes| JSON["✅ JSON\n- API response\n- Fast parsing"]
Q2 -->|No| Q3
Q3 -->|Simple| INI["✅ INI\n- Simple config\n- Legacy compat"]
Q3 -->|Medium| TOML["✅ TOML\n- Python/Rust\n- Clear syntax"]
Q3 -->|Complex| YAML["✅ YAML\n- Docker/K8s\n- Best readability"]
Start --> Q4{Documentation?}
Q4 -->|Yes| MD["✅ Markdown\n- README\n- Blog"]
Start --> Q5{Java project?}
Q5 -->|Yes| XML["✅ XML\n- Maven\n- Spring"]
Core Principles
# 1. API response → JSON
@app.get("/api/users")
def get_users():
return {"users": [...]} # JSON
# 2. Config file → YAML or TOML
# config.yaml
database:
host: localhost
port: 5432
# 3. Documentation → Markdown
# README.md
# My Project
This is a description.
# 4. Build config → By language
# package.json (Node.js)
# Cargo.toml (Rust)
# pom.xml (Java)
# 5. Simple config → INI
# app.ini
[database]
host = localhost
Pros and Cons Summary
| Format | Best Advantage | Biggest Disadvantage | Recommended Use |
|---|---|---|---|
| JSON | Fast parsing | No comments | API, data exchange |
| YAML | Readability | Slow parsing | Docker, K8s, CI/CD |
| XML | Schema validation | Verbose | Java, SOAP, RSS |
| TOML | Clear syntax | Limited support | Rust, Python config |
| INI | Simplicity | No standard | Simple config |
| Markdown | Easy to read | Limited data structure | Docs, README |
Best Practices
# ✅ Recommendations
# 1. Consistent indentation (YAML)
app:
name: MyApp # 2 spaces
version: 1.0.0
# 2. Use comments (YAML, TOML)
# Database configuration
[database]
host = "localhost" # localhost in dev environment
# 3. Separate environment variables
# config.yaml (version controlled)
database:
host: ${DB_HOST}
port: ${DB_PORT}
# .env (excluded from version control)
DB_HOST=localhost
DB_PORT=5432
# 4. Schema validation
# Use JSON Schema, YAML Schema
# 5. Encrypt sensitive information
# Use SOPS, Vault, etc.
Conversion Cheat Sheet
Command Line Tools
# JSON → YAML
cat config.json | yq -P > config.yaml
# YAML → JSON
cat config.yaml | yq -o=json > config.json
# JSON formatting
cat config.json | jq . > formatted.json
# YAML validation
yamllint config.yaml
# XML formatting
xmllint --format config.xml
# JSON merge
jq -s '.[0] * .[1]' base.json override.json > merged.json
# YAML merge
yq eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' base.yaml override.yaml
By Programming Language
# Python: All formats supported
import json # Built-in
import yaml # pip install pyyaml
import tomli # pip install tomli
import configparser # Built-in (INI)
import xml.etree.ElementTree as ET # Built-in
# JavaScript/Node.js
const json = require('./config.json'); # Native
const yaml = require('js-yaml');
const toml = require('toml');
const ini = require('ini');
# Go
import (
"encoding/json"
"gopkg.in/yaml.v3"
"github.com/BurntSushi/toml"
"gopkg.in/ini.v1"
)
# Rust
use serde_json; // JSON
use serde_yaml; // YAML
use toml; // TOML
Summary
One-line summary: Use JSON for APIs, YAML or TOML for config files, Markdown for documentation, XML for Java builds, but understand the pros and cons of each format and choose based on project requirements.
Frequently Asked Questions (FAQ)
Q. When would I use this in practice?
A. Characteristics and differences of frequently used file formats in programming including JSON, YAML, XML, TOML, INI.
Q. What should I read before this?
A. Follow the previous article or related articles links at the bottom of each post to learn in sequence.
Q. Where can I study this more deeply?
A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.
Related Articles (Internal Links)
Other articles related to this topic.
- Complete Astro Complete Guide | Static Sites
- Complete Character Encoding Complete Guide | ASCII· UTF-8
- Complete ChatGPT API Complete Guide | Usage· Pricing
Keywords Covered in This Article (Related Search Terms)
This article covers JSON, YAML, XML, TOML, INI, Markdown, Config, Configuration.