Postgres în Next.js
Baza de date doar pe server, Neon și pooling, cache pe tipuri de date, seed și migrații.
Actualizat
Ce înseamnă să legi Next.js de o bază de date
În Next.js, baza de date se accesează doar pe server: în Server Components, Server Actions și Route Handlers. Componenta din browser nu vorbește niciodată direct cu baza de date — trece mereu prin codul tău de server, care verifică cine cere și ce.
Aplicația asta e exact un astfel de proiect: Next.js 16 + Postgres pe Neon.
Postgres „serverless” — de ce Neon, Supabase, Vercel Postgres
O bază de date clasică ține conexiuni deschise permanent. Funcțiile serverless (Vercel) pornesc și se opresc des — fiecare ar deschide conexiuni noi și ar epuiza limita.
| Soluție | Cum rezolvă |
|---|---|
driver HTTP (@neondatabase/serverless) |
fiecare query e un request HTTP — fără conexiune de ținut |
connection pooling (PgBouncer, URL cu -pooler) |
un intermediar refolosește puține conexiuni reale |
| scale to zero | baza se oprește când nu e folosită (cost mic pentru proiecte personale) |
| branching (Neon) | copie instant a bazei pentru fiecare preview / PR |
Structura în proiect
.env.localDATABASE_URL — niciodată în Gitsrc/shared/api/db.tsclientul, cu import 'server-only'
entities/lesson/api/lesson-api.tsquery-uri cu 'use cache' + cacheTag
progress/api/progress-api.tscitiri per user (dinamice)save-progress.tsServer Action de scriere
db/schema.sqlstructura tabelelor
scripts/seed.tsdate inițiale
// shared/api/db.ts
import 'server-only'
import { neon } from '@neondatabase/serverless'
export const sql = neon(process.env.DATABASE_URL!)server-only face build-ul să eșueze dacă modulul ajunge vreodată într-un Client Component.
Citire, scriere, cache — tiparul complet
| Operație | Unde | Cache |
|---|---|---|
| date publice (lecții, produse) | funcție în entities/*/api |
'use cache' + cacheLife + cacheTag |
| date per user (progres, coș) | funcție care citește cookies() / sesiunea |
dinamic, în <Suspense> |
| scriere | Server Action: auth → validare Zod → query → updateTag / refresh() |
invalidare |
Toate trei sunt implementate în aplicația asta — vezi Cache și Server Actions.
Seed și date de test
Un seed populează baza cu date inițiale (conținutul lecțiilor de aici vine din npm run seed). Reguli: seed-ul e idempotent (rulat de două ori dă același rezultat — INSERT ... ON CONFLICT DO UPDATE), nu se rulează pe producție cu date de test.
Checklist de producție
DATABASE_URLsetat în Vercel separat pentru Production și Preview (ideal, branch Neon separat pentru preview).- URL-ul cu pooler pentru funcțiile serverless.
- Migrațiile rulate înainte de deploy-ul codului care depinde de ele.
- Indecși pe coloanele folosite în
WHEREșiJOIN. - Backup / point-in-time restore activat.
Pe scurt
- Baza de date doar pe server; clientul DB cu
server-only. - Serverless → driver HTTP sau pooling; Neon oferă și branching pe preview.
- Public →
'use cache'; per user → dinamic în Suspense; scrieri → Server Action + invalidare.