Umgebungsdatei-Formatierer

Formatieren und validieren Sie .env-Dateien mit Syntaxhervorhebung

What is .env File Formatting?

Environment file formatting transforms inconsistently structured .env files into a clean, readable format with consistent spacing, proper quoting, logical grouping, and standardized line endings. The .env file format — popularized by the twelve-factor app methodology — stores application configuration as KEY=VALUE pairs that are loaded into environment variables at runtime. While the format appears trivially simple, real-world .env files accumulate formatting inconsistencies over time: mixed quoting styles, irregular spacing around equals signs, missing blank lines between logical sections, and trailing whitespace that causes subtle parsing differences across dotenv implementations.

A well-formatted environment file improves readability during code reviews, reduces merge conflicts in version control, and prevents parsing bugs caused by invisible characters or inconsistent quoting. This tool normalizes your .env files to follow community conventions without altering the semantic content — variable names and their effective values remain identical after formatting.

The .env File Format and KEY=VALUE Syntax

The .env format originated with the Ruby dotenv gem and has since been adopted across virtually every language ecosystem — Node.js (dotenv), Python (python-dotenv), Go (godotenv), PHP (vlucas/phpdotenv), and Rust (dotenvy). Despite widespread use, there is no formal specification — behavior varies between implementations. The core syntax rules that most parsers agree on are:

  • Basic assignment: KEY=value assigns the string value to the variable KEY. No spaces around the equals sign in most implementations — KEY = value may be interpreted differently (some parsers include the spaces in the key or value).
  • Comments: Lines starting with # are comments and ignored by parsers. Inline comments after values (KEY=value # comment) are supported by some implementations (Docker Compose, bash) but not others (Node.js dotenv treats everything after = as the value).
  • Quoting: Values can be unquoted, single-quoted, or double-quoted. Double-quoted values support escape sequences (\n, \t, \\) and variable interpolation in some parsers. Single-quoted values are treated as literal strings with no escape processing. Unquoted values are trimmed of trailing whitespace by most parsers.
  • Empty values: KEY= sets the variable to an empty string. Omitting the equals sign entirely (KEY) is handled inconsistently — some parsers skip it, others set it to an empty string. Best practice is to always include the equals sign.
  • Multiline values: Double-quoted values can span multiple lines in most implementations. The newlines are preserved as literal \n characters in the variable value. This is commonly used for private keys, certificates, and JSON configuration blobs.

Common Formatting Issues and How the Formatter Resolves Them

Environment files degrade over time as different developers add variables with inconsistent styles. A formatter normalizes these inconsistencies while preserving semantic meaning:

  • Inconsistent quoting: Some values quoted, others not — even when quoting is unnecessary. The formatter applies a consistent quoting strategy: quote values that contain spaces, special characters, or hash symbols; leave simple alphanumeric values unquoted.
  • Spacing around =: Mixing KEY=value, KEY =value, and KEY = value in the same file. The formatter removes all spaces around the equals sign to follow the most portable convention supported by all parsers.
  • Trailing whitespace: Invisible spaces or tabs at the end of lines cause values to include unexpected whitespace in some parsers. The formatter strips all trailing whitespace.
  • Missing section separators: Related variables (database config, API keys, feature flags) grouped together without blank lines between sections. The formatter can insert blank lines between logical groups detected by variable name prefixes (e.g., DB_, AWS_, SMTP_).
  • Inconsistent line endings: Mixed \r\n (Windows) and \n (Unix) line endings that cause diff noise in version control. The formatter normalizes to \n for maximum compatibility with Docker, Linux servers, and CI environments.
  • Duplicate keys: The same variable defined multiple times — later definitions silently override earlier ones in most parsers, leading to confusion. The formatter detects and flags duplicates so developers can resolve them intentionally.

Docker and docker-compose Environment Variable Handling

Docker has its own conventions for environment variables that extend beyond the basic dotenv format. Understanding these differences is essential when formatting .env files used in containerized deployments:

  • docker-compose env_file directive: Docker Compose loads .env files specified in the env_file section of each service. It uses its own parser that supports inline comments (KEY=value # comment), which differs from Node.js dotenv. The formatter preserves comment positions that are valid in Docker contexts.
  • The project-level .env file: Docker Compose automatically reads a .env file in the project root for variable substitution in docker-compose.yml. Variables defined there are used to expand ${VARIABLE} references in the Compose file — they are not automatically injected into containers unless also listed in environment or env_file.
  • Build-time vs runtime variables: ARG in Dockerfiles are build-time variables that do not persist in the final image. ENV directives bake values into image layers permanently. For secrets, prefer runtime injection via docker run --env-file rather than embedding in build layers.
  • Variable interpolation: Docker Compose supports ${VAR:-default} syntax for default values and ${VAR:?error} for required variables. These shell-style expansions should not be altered by the formatter — they are intentional syntax, not formatting issues.

Node.js dotenv Ecosystem and Parsing Behavior

The Node.js dotenv package (70+ million weekly npm downloads) is the de facto standard for loading .env files in JavaScript applications. Understanding its parsing behavior helps write .env files that work reliably across the Node.js ecosystem:

  • No inline comments: Unlike Docker Compose, the standard dotenv package does not support inline comments. Writing PORT=3000 # HTTP port sets the value to 3000 # HTTP port — the entire string after the equals sign. Use full-line comments above the variable instead.
  • Variable expansion: The dotenv-expand companion package enables ${VARIABLE} references within values. Without it, $ characters are treated as literal text. The formatter preserves these references without modification.
  • Multiline handling: Double-quoted values can span lines: PRIVATE_KEY="-----BEGIN RSA...\n...\n-----END RSA...". The dotenv parser processes \n escape sequences inside double quotes into actual newline characters. Single-quoted values preserve \n as the literal two-character sequence.
  • Precedence: By default, dotenv does not override existing environment variables. If PORT is already set in the shell environment, the .env value is ignored. This behavior ensures deployment environment variables take precedence over development defaults, but can cause confusion during debugging.
  • Framework conventions: Next.js, Vite, and Create React App prefix client-exposed variables with NEXT_PUBLIC_, VITE_, or REACT_APP_ respectively. Only prefixed variables are embedded in client bundles — all others remain server-side only. The formatter preserves and recognizes these prefixes as logical grouping boundaries.

Code Examples

Well-Formatted .env File Following Community Conventions

# ==================================
# Application Configuration
# ==================================
NODE_ENV=production
APP_NAME=my-api
APP_PORT=3000
APP_URL=https://api.example.com

# ==================================
# Database Configuration
# ==================================
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp_production
DB_USER=app_user
DB_PASSWORD="p@ss\"word with special chars"

# ==================================
# External Services
# ==================================
REDIS_URL=redis://cache.internal:6379/0
SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_USER=apikey
SMTP_PASSWORD="SG.xxxxxxxxxxxxxxxxxxxx"

# ==================================
# Feature Flags
# ==================================
ENABLE_CACHE=true
ENABLE_RATE_LIMIT=true
MAX_UPLOAD_SIZE=10485760

# Multiline value (private key for JWT signing)
JWT_PRIVATE_KEY="-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIODr...base64content...
-----END EC PRIVATE KEY-----"

Output:

# Formatting conventions applied:
# - No spaces around = sign
# - Section headers with blank line separators
# - Logical grouping by prefix (DB_, SMTP_, etc.)
# - Double quotes only when value contains special characters
# - Comments on their own line (not inline)
# - Consistent Unix line endings (LF)
# - No trailing whitespace

Loading .env Files in Node.js with dotenv

// Load .env file into process.env
import 'dotenv/config';

// Or with explicit configuration
import { config } from 'dotenv';
import { expand } from 'dotenv-expand';

const env = config({ path: '.env.production' });
expand(env); // Enable ${VARIABLE} expansion

// Access formatted environment variables
const dbConfig = {
  host: process.env.DB_HOST,
  port: parseInt(process.env.DB_PORT || '5432', 10),
  database: process.env.DB_NAME,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
};

// Validate required variables are present
const required = ['DB_HOST', 'DB_NAME', 'DB_USER', 'DB_PASSWORD'];
const missing = required.filter(key => !process.env[key]);
if (missing.length > 0) {
  throw new Error(`Missing required env vars: ${missing.join(', ')}`);
}

Docker Compose with .env File Integration

# docker-compose.yml — uses .env file for variable substitution
version: "3.8"

services:
  api:
    build: .
    ports:
      - "${APP_PORT:-3000}:3000"
    env_file:
      - .env              # Loaded into container environment
      - .env.local        # Override for local development
    environment:
      - NODE_ENV=production  # Explicit override
      - DB_HOST=db           # Container networking override

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: ${DB_NAME}
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata: