version: '3.8'
services:
postgres:
image: postgres:16-alpine
container_name: app_postgres
restart: always
environment:
POSTGRES_USER: dev_user
POSTGRES_PASSWORD: dev_password
POSTGRES_DB: app_db
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U dev_user -d app_db"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
container_name: app_redis
restart: always
ports:
- "6379:6379"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 5
web:
build:
context: .
dockerfile: Dockerfile.dev
container_name: app_web
restart: always
ports:
- "3000:3000"
environment:
DATABASE_URL: "postgresql://dev_user:dev_password@postgres:5432/app_db?schema=public"
REDIS_URL: "redis://redis:6379"
volumes:
- .:/app
- /app/node_modules
- /app/.next
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
volumes:
postgres_data:
redis_data:Am pierdut jumătate de zi săptămâna trecută configurând mediul local pentru un coleg nou. Avea deja Node instalat, dar Postgres-ul local intra în conflict de porturi cu alt proiect, iar Redis lipsea complet. Am decis că e momentul să terminăm cu improvizațiile și să trântesc un docker-compose.yml curat pe care să-l folosească toată echipa fără dureri de cap.
Miza e simplă: vrei docker compose up și totul să meargă din prima. Fără pachete instalate prin Homebrew, fără WSL configurat jumătate de zi și fără servicii lăsate uitat în fundal care-ți mănâncă resurse duminica. Pe un proiect recent cu 12k utilizatori activi și stack clasic — Next.js (App Router), Prisma, Postgres 16 și Redis — setup-ul ăsta ne-a redus timpul de onboarding de la 3 ore la sub 2 minute.
Ce trebuie să ai în vedere la Next.js în Docker
Prima capcană în care cad mulți la început este să trateze containerul de dev ca pe cel de producție. În dev ai nevoie de Hot Reload (HMR) instant și acces rapid la loguri. Dacă bagi Next.js în container, riscul cel mai mare este un HMR leneș, cu 3-4 secunde întârziere, mai ales pe macOS din cauza stratului de virtualizare a fișierelor.
Ca să eviți asta, faci un bind mount pentru codul sursă (.:/app), dar izolezi node_modules și .next prin volume anonime (/app/node_modules). Altfel, dependențele compilate din container se vor suprapune cu cele de pe host sau vor fi suprascrise când dai un npm install local.
Al doilea truc critic este healthcheck-ul pentru Postgres și Redis. Aplicația Next.js încearcă adesea să se conecteze la DB la pornire (de exemplu, când Prisma își inițializează clientul). Dacă containerul de app pornește în același timp cu Postgres, dar baza de date încă își inițializează fișierele, aplicația ta va crăpa instant cu eroarea clasică ECONNREFUSED. Cu condition: service_healthy în depends_on, Next.js așteaptă cuminte până când Postgres chiar răspunde la comenzi.
Trade-off-uri reale
Nu există configurație perfectă, doar alegeri asumate. Docker Compose în dev local îți oferă izolare totală și garanția că mediile tuturor devilor sunt identice 1:1. Nu mai auzi niciodată replica "la mine pe mașină mergea".
Răul necesar? Consumul de resurse. Pe un Mac cu cip M1/M2 sau un laptop cu 16GB RAM, Docker Desktop mănâncă lejer 3-4GB RAM doar ca să existe. Dacă ai și un Chrome cu 20 de tab-uri deschise și un VS Code încărcat cu extensii, s-ar putea ca ventilatoarele să înceapă să zbiere.
Cum arată setup-ul optim
În codul atașat ai un exemplu gata de folosit. Am folosit volume denumite (named volumes) pentru directoarele de date ale bazelor de date. Nu folosi niciodată căi relative pe disk-ul local (gen ./data/postgres) pentru stocarea datelor din DB, fiindcă I/O-ul devine dezastruos de lent pe Docker Desktop din cauza sincronizării fișierelor între sistemul gazdă și VM-ul de Docker.
Voi ce abordare folosiți în proiectele voastre? Rulați aplicația direct pe host și doar baze de date în Docker, sau băgați tot stack-ul în containere?