Sonamuλ νκ²½λ³λ‘ λ€λ₯Έ μ€μ μ μ μ©νκΈ° μν΄ .env νμΌμ μ¬μ©ν©λλ€. λ°μ΄ν°λ² μ΄μ€ μ°κ²° μ 보, API ν€, μΈμ
λΉλ°ν€ λ± λ―Όκ°ν μ 보λ .env νμΌμ μ μ₯νκ³ sonamu.config.tsμμ μ°Έμ‘°ν©λλ€.
.env νμΌμ μ λ Gitμ 컀λ°νλ©΄ μ λ©λλ€! .gitignoreμ .envκ° ν¬ν¨λμ΄ μλμ§ νμΈνμΈμ.
λΉ λ₯Έ μμ
.env.example 볡μ¬
νλ‘μ νΈ λ£¨νΈμμ .env.exampleμ 볡μ¬νμ¬ .env νμΌμ μμ±ν©λλ€. νκ²½λ³μ μ€μ
.env νμΌμ μ΄μ΄ μ€μ κ°μΌλ‘ μμ ν©λλ€.# μμ
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=your-db-password
μ€μ νμΌμμ μ°Έμ‘°
sonamu.config.tsμμ process.envλ‘ νκ²½λ³μλ₯Ό μ½μ΅λλ€.database: {
defaultOptions: {
connection: {
host: process.env.DB_HOST || "0.0.0.0",
password: process.env.DB_PASSWORD,
},
},
}
.env νμΌ κ΅¬μ‘°
.env νμΌμ KEY=VALUE νμμΌλ‘ μμ±ν©λλ€.
# νλ‘μ νΈ μ€μ
PROJECT_NAME=MyProject
# λ°μ΄ν°λ² μ΄μ€
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=your-db-password
# μΈμ
SESSION_SECRET=your-session-secret # μ΅μ 64μ
SESSION_SALT=your-session-salt # μ΅μ 16μ
# μ€ν λ¦¬μ§ (fs λλ s3)
DRIVE_DISK=fs
# AWS S3 (DRIVE_DISK=s3μΌ λ)
AWS_ACCESS_KEY_ID=your-aws-access-key-id
AWS_SECRET_ACCESS_KEY=your-aws-secret-access-key
S3_REGION=ap-northeast-2
S3_BUCKET=my-bucket
# μΈλΆ API
OPENAI_API_KEY=your-openai-api-key
# μ컀
DISABLE_WORKER=false
μ£Όμμ #μΌλ‘ μμν©λλ€. λΉ μ€μ 무μλ©λλ€.
νκ²½λ³ μ€μ
κ°λ° νκ²½
μ€ν
μ΄μ§
νλ‘λμ
# λ‘컬 κ°λ°μ© μ€μ
PROJECT_NAME=MyProject-Dev
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=your-dev-password
DATABASE_NAME=myproject_dev
SESSION_SECRET=your-dev-session-secret
SESSION_SALT=your-dev-session-salt
DRIVE_DISK=fs
# κ°λ°μ© OpenAI (μ ν)
OPENAI_API_KEY=sk-***
DISABLE_WORKER=false
νΉμ§:
- λ‘컬 λ°μ΄ν°λ² μ΄μ€ μ¬μ©
- νμΌ μμ€ν
μ€ν 리μ§
- κ°λ¨ν λΉλ°ν€ (보μ λΆνμ)
# ν
μ€νΈ μλ²μ© μ€μ
PROJECT_NAME=MyProject-Staging
DB_HOST=staging-db.example.com
DB_PORT=5432
DB_USER=myproject_user
DB_PASSWORD=your-staging-password # μ΅μ 32μ
DATABASE_NAME=myproject_staging
SESSION_SECRET=your-staging-session-secret # μ΅μ 64μ
SESSION_SALT=your-staging-session-salt
DRIVE_DISK=s3
AWS_ACCESS_KEY_ID=your-staging-aws-key-id
AWS_SECRET_ACCESS_KEY=your-staging-aws-secret-key
S3_REGION=ap-northeast-2
S3_BUCKET=myproject-staging
OPENAI_API_KEY=your-staging-openai-key
DISABLE_WORKER=false
νΉμ§:
- μ격 λ°μ΄ν°λ² μ΄μ€
- S3 μ€ν 리μ§
- νλ‘λμ
κ³Ό μ μ¬ν νκ²½
# μ€μλ²μ© μ€μ
PROJECT_NAME=MyProject
DB_HOST=prod-db.example.com
DB_PORT=5432
DB_USER=myproject_prod
DB_PASSWORD=your-production-password # μ΅μ 64μ
DATABASE_NAME=myproject_prod
SESSION_SECRET=your-production-session-secret # μ΅μ 64μ
SESSION_SALT=your-production-session-salt
DRIVE_DISK=s3
AWS_ACCESS_KEY_ID=your-production-aws-key-id
AWS_SECRET_ACCESS_KEY=your-production-aws-secret-key
S3_REGION=ap-northeast-2
S3_BUCKET=myproject-production
OPENAI_API_KEY=your-production-openai-key
DISABLE_WORKER=false
νΉμ§:
- κ³ κ°μ©μ± λ°μ΄ν°λ² μ΄μ€
- S3 μ€ν λ¦¬μ§ (νμ₯μ±)
- κ°λ ₯ν 보μ ν€
sonamu.config.ts μ°λ
νκ²½λ³μλ₯Ό sonamu.config.tsμμ μ¬μ©νλ λ°©λ²μ
λλ€.
κΈ°λ³Έ ν¨ν΄
import { defineConfig } from "sonamu";
export default defineConfig({
projectName: process.env.PROJECT_NAME ?? "DefaultName",
database: {
name: process.env.DATABASE_NAME ?? "database_name",
defaultOptions: {
connection: {
host: process.env.DB_HOST || "0.0.0.0",
port: Number(process.env.DB_PORT) || 5432,
user: process.env.DB_USER || "postgres",
password: process.env.DB_PASSWORD,
},
},
},
// ...
});
Nullish Coalescing vs OR
// κΆμ₯: undefined/nullλ§ λ체
const name = process.env.PROJECT_NAME ?? "DefaultName";
// undefined, null β "DefaultName"
// ""(λΉ λ¬Έμμ΄) β "" μ μ§
// 0 β 0 μ μ§
νκ²½λ³μκ° μ€μ λμ§ μμμ λλ§ κΈ°λ³Έκ°μ μ¬μ©νλ €λ©΄ ??λ₯Ό μ¬μ©νμΈμ. ||λ λΉ λ¬Έμμ΄λ falsyλ‘ μ²λ¦¬ν©λλ€.
μ«μ λ³ν
// β
μ¬λ°λ₯Έ λ°©λ²
port: Number(process.env.DB_PORT) || 5432
// β μλͺ»λ λ°©λ²
port: process.env.DB_PORT || 5432 // λ¬Έμμ΄ "5432"κ° λ μ μμ
λΆλ¦° λ³ν
// β
μ¬λ°λ₯Έ λ°©λ²
enableWorker: !["true", "1"].includes(process.env.DISABLE_WORKER ?? "false")
// λλ
enableCache: process.env.ENABLE_CACHE === "true"
// β μλͺ»λ λ°©λ²
enableCache: process.env.ENABLE_CACHE || false // "false"λ truthy
보μ λͺ¨λ² μ¬λ‘
κ°λ ₯ν λΉλ°ν€ μμ±νκΈ°
# 64μ λλ€ λ¬Έμμ΄ μμ±
openssl rand -base64 48
# λλ
node -e "console.log(require('crypto').randomBytes(48).toString('base64'))"
SESSION_SECRET μμ:SESSION_SECRET=your-64-character-random-session-secret-change-in-production
μ΅μ κΈΈμ΄:
- SESSION_SECRET: 64μ μ΄μ
- SESSION_SALT: 16μ μ΄μ
- DB_PASSWORD: 32μ μ΄μ (νλ‘λμ
)
.gitignore μ€μ
# νκ²½λ³μ
.env
.env.local
.env.*.local
# νλ‘λμ
νκ²½λ³μλ μ λ μ»€λ° κΈμ§
.env.production
# ν
μ€νΈμ©λ νμ©ν μ μμ (λ―Όκ° μ 보 μλ€λ©΄)
# .env.test
.env.example μ μ§
# μ€μ κ° μμ΄ ν€λ§ λμ΄
PROJECT_NAME=
DB_HOST=localhost
DB_PORT=5432
DB_USER=
DB_PASSWORD=
SESSION_SECRET=
SESSION_SALT=
.env.exampleμ Gitμ 컀λ°νμ¬ νμλ€μ΄ μ°Έκ³ νλλ‘ ν©λλ€.
νμΌ κΆν μ€μ
# .env νμΌ κΆνμ μμ μλ§ μ½κΈ°/μ°κΈ°
chmod 600 .env
# νμΈ
ls -la .env
# -rw------- 1 user user 512 Jan 09 10:00 .env
νκ²½λ³μ μ κ·Ό μ ν
// β
νμν κ³³μμλ§ μ κ·Ό
const dbPassword = process.env.DB_PASSWORD;
// β λ‘κ·Έμ μΆλ ₯ κΈμ§
console.log("Password:", process.env.DB_PASSWORD);
// β ν΄λΌμ΄μΈνΈμ λ
ΈμΆ κΈμ§
res.send({ secret: process.env.SESSION_SECRET });
GitHub Actions
.github/workflows/deploy.yml
jobs:
deploy:
steps:
- name: Deploy
env:
DB_HOST: ${{ secrets.DB_HOST }}
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
SESSION_SECRET: ${{ secrets.SESSION_SECRET }}
run: |
npm run deploy
Vercel/Netlify
- νλ‘μ νΈ μ€μ β Environment Variables
- κ° λ³μλ₯Ό κ°λ³ μΆκ°
- νκ²½λ³λ‘ λ€λ₯Έ κ° μ€μ (Production/Preview/Development)
νλ‘λμ
λΉλ°ν€λ μ λ κ°λ°/μ€ν
μ΄μ§ νκ²½μ μ¬μ©νμ§ λ§μΈμ!
λ¬Έμ ν΄κ²°
νκ²½λ³μκ° undefined
μ¦μ: process.env.DB_PASSWORDκ° undefinedμμΈ:
.env νμΌμ΄ μμ
.env νμΌ μμΉκ° μλͺ»λ¨
- λ³μ μ΄λ¦ μ€ν
- μλ² μ¬μμ μ ν¨
ν΄κ²°:# 1. .env νμΌ νμΈ
cat .env | grep DB_PASSWORD
# 2. .env νμΌ μμΉ νμΈ (νλ‘μ νΈ λ£¨νΈ)
ls -la .env
# 3. μλ² μ¬μμ
npm run dev
νκ²½λ³μ κ°μ΄ μ μ© μ λ¨
μ¦μ: νκ²½λ³μ λ³κ²½νλλ° μ¬μ ν μ΄μ κ° μ¬μ©μμΈ:
- Node.js νλ‘μΈμ€κ° μμν λλ§
.env νμΌμ μ½μ
- νμΌ λ³κ²½ ν μλ² μ¬μμ νμ
ν΄κ²°:# κ°λ° μλ² μ¬μμ
# Ctrl+Cλ‘ μ’
λ£ ν
npm run dev
HMR(Hot Module Replacement)μ μ½λλ§ μλ 리λ‘λνλ©°, νκ²½λ³μλ μ¬μμν΄μΌ μ μ©λ©λλ€.
νλ‘λμ
μμ νκ²½λ³μ λ‘λ μ€ν¨
μ¦μ: λ‘컬μ λλλ° νλ‘λμ
μμ undefinedμμΈ:
- νλ‘λμ
μλ²μ
.env νμΌμ΄ μμ
- νΈμ€ν
νλ«νΌμ νκ²½λ³μ μ€μ λ―ΈλΉ
ν΄κ²°:λ°©λ² 1: μλ²μ .env νμΌ λ°°ν¬# SSHλ‘ μ μ ν
cd /path/to/app
nano .env
# λ΄μ© λΆμ¬λ£κΈ° ν μ μ₯
λ°©λ² 2: νΈμ€ν
νλ«νΌ νκ²½λ³μ μ¬μ©
- Vercel: Project Settings β Environment Variables
- AWS EC2:
/etc/environment λλ ~/.bashrc
- Docker:
docker run -e DB_HOST=... -e DB_PASSWORD=...
λ€μ λ¨κ³