2026-06-01
ORM e migrazioni in serverless: criteri operativi
Griglia comparativa su migrazioni, cold start e type-safety tra ORM diffusi senza nominare un vincitore assoluto.
Prisma, Drizzle, TypeORM (e altri) competono su ergonomia. In serverless Node ciò che conta di più è: dimensione cold bundle, modello migrazioni, connessioni DB e predictability del query planner. Questo articolo propone una griglia di punteggio, non un vincitore universale—dipende dal provider (Neon, RDS Proxy, SQLite), dal runner (Lambda, Cloud Run, Nitro node-server), dalla versione esatta della libreria.
Vincoli serverless
- Cold start: import pesanti (
@prisma/clientgeneration,reflect-metadataper TypeORM) aumentano ms al primo invocazione. - Connessioni: senza pooler, ogni istanza Lambda può aprire N socket—usa PgBouncer/Neon pool o limita concorrenza.
- Filesystem: alcuni ORM assumono
schema.prismao migrazioni locali; in container immutabili devi bake file o eseguire migrazioni in step di deploy, non al cold start.
Migrazioni: ownership
Domande da punteggio 1–5:
- Le migrazioni sono file versionati applicate in CI (
migrate deploy)? - Puoi squashare o rebasare storie lunghe senza drama?
- Esiste drift detection (schema DB ≠ atteso)?
- Rollback documentato o solo forward-only accettabile?
Drizzle spesso punta su SQL-first + migrazioni TS/SQL esplicite; Prisma con prisma migrate; TypeORM con CLI migration:run—verifica la doc della versione che usi.
Type-safety
- Compile-time: modelli generati vs inferiti da schema.
- Runtime: parsing dei risultati (Drizzle/Zod overlay, ecc.).
Chi promette “type-safe” ma genera any su query raw perde punti operativi.
Osservabilità
Puoi loggare query parametrizzate in dev senza esporre PII? Esiste hook centrale ($on('query') Prisma, logger Drizzle) compatibile con il tuo log sink?
Griglia esempio (con una misura cold import reale)
Metodo (maggio 2026, macOS arm64): per ogni libreria, un processo node nuovo; Drizzle e TypeORM con await import('…') (ESM); Prisma con require('@prisma/client') dopo prisma generate su schema SQLite minimale. Versioni pin: @prisma/client 6.3.0, drizzle-orm 0.39.1, typeorm 0.3.21. I millisecondi cambiano con CPU, disco, versione Node e presenza di altri import nel bundle — ripeti nel tuo deploy.
| Criterio | Peso | Prisma 6.3.0 | Drizzle 0.39.1 | TypeORM 0.3.21 |
|---|---|---|---|---|
| Cold import (ms, processo nuovo) | 3 | ~15 | ~73 | ~85 |
| Storia migrazioni (1–5, soggettivo) | 3 | 5 | 4 | 3 |
| Query DX (1–5, soggettivo) | 2 | 5 | 4 | 3 |
| Peso bundle (1–5, misura tu) | 2 | — | — | — |
La riga bundle va riempita con webpack-bundle-analyzer / output Rolldown o report serverless del vendor: qui non abbiamo un’app unica di riferimento.
Misura rapida Prisma (stesso processo, dopo generate):
node -e "const {performance}=require('node:perf_hooks');const t=performance.now();require('@prisma/client');console.log((performance.now()-t).toFixed(1)+' ms')"
Driver TCP vs “serverless HTTP/WebSocket” (Postgres)
Il collo di bottiglia in serverless non è solo l’ORM ma aprire centinaia di connessioni TCP da altrettante istanze fredde. Prisma separa oggi database drivers classici da serverless driver adapters: l’accoppiata documentata con Neon (@prisma/adapter-neon + @neondatabase/serverless, canale WebSocket) è l’esempio d’archivio—guida Prisma × Neon. Cerca analoghi se usi altri vendor HTTP/libSQL.
Drizzle spesso si abbina a driver neon-http o a pooler gestiti—segui il Getting Started per il dialetto scelto.
Senza adapter/pooler, misura too many connections prima di incolpare “ORM lento”.
Serverless + SQLite
Se usi SQLite embedded (better-sqlite3), Prisma/TypeORM hanno storie diverse da Postgres; Drizzle supporta SQLite con API simile a SQL leggero. Non confrontare “ORM generico” senza nominare il dialetto.
Sintesi
Scegli l’ORM dopo misurazione cold start nel tuo deploy reale e dopo aver definito chi applica migrazioni (CI vs runtime). Le opinioni Twitter contano meno di questi due vincoli.
Documentazione: siti ufficiali Prisma, Drizzle, TypeORM per comandi aggiornati.