Hardcoding database passwords, hostnames, and feature flags directly in `docker-compose.yml` makes the file non-portable and creates security risks when the ...
Hardcoding database passwords, hostnames, and feature flags directly in docker-compose.yml makes the file non-portable and creates security risks when the Compose file is committed to version control. Docker Compose natively reads a .env file in the same directory, allowing you to separate configuration from infrastructure definition.
Real-world example: You maintain a single docker-compose.yml that works across development, staging, and production by swapping only the .env file.
# n8n Configuration
N8N_VERSION=1.94.1
N8N_HOST=n8n.example.com
N8N_PROTOCOL=https
GENERIC_TIMEZONE=America/New_York
# Database
POSTGRES_DB=n8n_db
POSTGRES_USER=n8n_user
POSTGRES_PASSWORD=a-strong-random-password-here
POSTGRES_VERSION=16
# Execution Settings
EXECUTIONS_DATA_PRUNE=true
EXECUTIONS_DATA_MAX_AGE=168
# Encryption key for credentials (generate once, never change)
N8N_ENCRYPTION_KEY=your-generated-encryption-key
```text
```yaml title="docker-compose.yml"
services:
postgres:
image: postgres:${POSTGRES_VERSION}-alpine
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
n8n:
image: n8nio/n8n:${N8N_VERSION}
environment:
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_DATABASE: ${POSTGRES_DB}
DB_POSTGRESDB_USER: ${POSTGRES_USER}
DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD}
N8N_HOST: ${N8N_HOST}
N8N_PROTOCOL: ${N8N_PROTOCOL}
GENERIC_TIMEZONE: ${GENERIC_TIMEZONE}
EXECUTIONS_DATA_PRUNE: ${EXECUTIONS_DATA_PRUNE}
EXECUTIONS_DATA_MAX_AGE: ${EXECUTIONS_DATA_MAX_AGE}
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
```text
```bash title=".gitignore"
# Never commit secrets
.env
```text
> **Danger: The Encryption Key**
>
> `N8N_ENCRYPTION_KEY` encrypts all stored credentials. If you lose this key, every credential in n8n becomes unreadable and must be re-entered. Generate it once with `openssl rand -hex 32`, store it in your `.env` file, and back it up separately from the database.
This pattern keeps secrets out of version control, makes environment promotion straightforward, and lets you generate environment-specific configs from a template.
**Related:** [Set a Unique Encryption Key and Back It Up](../security-best-practices/01-set-a-unique-encryption-key-and-back-it-up.md) | [Configure Payload Size and Binary Data Mode for Large Files](../performance-and-large-files/01-configure-payload-size-and-binary-data-mode-for-large-files.md)
I build production n8n and Cloudflare automation for teams — the same engineering behind HarperFlow. Fixed-price, escrow-protected, US-based.