Drizzle ORM és Next.js App Router: Adatbázis-integráció a nullától a produkcióig

Lépésről lépésre útmutató a Drizzle ORM integrálásához Next.js App Routerrel: telepítés, séma, migrációk, Server Components lekérdezések, CRUD műveletek, Zod validáció és produkciós connection pooling — működő kódpéldákkal.

Drizzle ORM + Next.js Setup Tutorial 2026

Bevezetés: Miért pont a Drizzle ORM a legjobb választás Next.js-hez 2026-ban?

Ha valaha is próbáltál adatbázist integrálni egy Next.js App Router projektbe, akkor pontosan tudod, milyen érzés elveszni az ORM-ek tengerében. Prisma, TypeORM, Kysely — a lista hosszú. De 2026-ban szerintem a Drizzle ORM egyértelműen kitűnik a mezőnyből. Könnyűsúlyú, típusbiztos, és natívan illeszkedik a Server Components meg a Server Actions világába. Nincs kódgenerálási lépés, nincs bináris fájl — csak tiszta TypeScript, ami úgy néz ki, mint az SQL, amit már ismersz.

Na de miért is mondom ezt ilyen magabiztosan?

Mert tényleg kipróbáltam éles projektben, és a különbség érezhető. Ebben az útmutatóban végigvezetlek a teljes folyamaton: a Drizzle ORM telepítésétől kezdve a séma definiáláson, migrációkon és Server Components lekérdezéseken át egészen a Server Actions CRUD műveletekig, Zod validációig és a produkciós connection pooling beállításáig. Minden kódrészlet működőképes és azonnal használható a saját projektedben.

Telepítés és projekt beállítás

Kezdjük a szükséges csomagok telepítésével. Feltételezem, hogy már van egy működő Next.js App Router projekted — ha még nincs, futtasd a npx create-next-app@latest parancsot TypeScript támogatással, és máris jöhetsz vissza.

npm install drizzle-orm @neondatabase/serverless
npm install -D drizzle-kit

Gyors összefoglaló, hogy mi micsoda: a drizzle-orm a fő ORM csomag, a @neondatabase/serverless a Neon PostgreSQL szerverless drivere (ha hagyományos PostgreSQL-t használsz, cseréld le a pg csomagra), a drizzle-kit pedig a migrációkezelő CLI eszköz.

A javasolt mappastruktúra a következő:

src/
├── app/
│   ├── page.tsx
│   └── actions/
│       └── tasks.ts          # Server Actions
├── db/
│   ├── schema.ts             # Drizzle séma
│   ├── index.ts              # DB kapcsolat
│   └── migrations/           # Generált migrációk
├── lib/
│   └── validators.ts         # Zod sémák
drizzle.config.ts              # Drizzle Kit konfiguráció
.env.local                     # Környezeti változók

Természetesen ez nem kötelező — de tapasztalatom szerint ez a felépítés a legjobban skálázódik, ahogy nő a projekt.

Adatbázis-kapcsolat konfigurálása

A Drizzle ORM nem kezeli önmaga a kapcsolatokat — te hozod a saját driveredet. Ez elsőre talán kényelmetlennek tűnik, de valójában óriási előny a rugalmasság szempontjából. Könnyedén válthatsz Neon, Supabase, PlanetScale vagy hagyományos PostgreSQL között anélkül, hogy az ORM rétegen bármit változtatnál.

Hozd létre a src/db/index.ts fájlt:

Neon szerverless driver használata

// src/db/index.ts
import { neon } from "@neondatabase/serverless";
import { drizzle } from "drizzle-orm/neon-http";
import * as schema from "./schema";

const sql = neon(process.env.DATABASE_URL!);
export const db = drizzle(sql, { schema });

Hagyományos PostgreSQL (node-postgres) használata

// src/db/index.ts
import { drizzle } from "drizzle-orm/node-postgres";
import { Pool } from "pg";
import * as schema from "./schema";

const pool = new Pool({
  connectionString: process.env.DATABASE_URL!,
  max: 10,
  ssl: process.env.NODE_ENV === "production"
    ? { rejectUnauthorized: false }
    : false,
});

export const db = drizzle(pool, { schema });

Fontos: soha ne hozz létre adatbázis-kapcsolatot a modul betöltésekor szerverless környezetben közvetlen kapcsolattal. A Neon szerverless drivere HTTP-alapú, szóval ez ott nem probléma — de a pg Pool esetén figyelj arra, hogy a kapcsolat csak szükség esetén jöjjön létre.

Add hozzá a .env.local fájlhoz a kapcsolati sztringet:

DATABASE_URL=postgresql://user:password@host:5432/dbname?sslmode=require

Séma definiálás TypeScriptben

Na, ez az a pont, ahol a Drizzle ORM igazán megmutatja az erejét. A séma maga TypeScript — nincsen külön DSL, nincsen generálási lépés, nincsen semmi varázslat. A típusok automatikusan levezetődnek, és a séma egyben a migrációk meg a Zod validátorok forrása is.

Őszintén? Ez az, ami engem meggyőzött.

// src/db/schema.ts
import {
  pgTable,
  serial,
  text,
  varchar,
  boolean,
  timestamp,
  integer,
} from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";

// Projektek tábla
export const projects = pgTable("projects", {
  id: serial("id").primaryKey(),
  name: varchar("name", { length: 255 }).notNull(),
  description: text("description"),
  createdAt: timestamp("created_at").defaultNow().notNull(),
  updatedAt: timestamp("updated_at")
    .defaultNow()
    .notNull()
    .$onUpdate(() => new Date()),
});

// Feladatok tábla
export const tasks = pgTable("tasks", {
  id: serial("id").primaryKey(),
  title: varchar("title", { length: 255 }).notNull(),
  description: text("description"),
  completed: boolean("completed").default(false).notNull(),
  priority: integer("priority").default(0).notNull(),
  projectId: integer("project_id")
    .references(() => projects.id, { onDelete: "cascade" })
    .notNull(),
  createdAt: timestamp("created_at").defaultNow().notNull(),
  updatedAt: timestamp("updated_at")
    .defaultNow()
    .notNull()
    .$onUpdate(() => new Date()),
});

// Relációk definiálása
export const projectsRelations = relations(projects, ({ many }) => ({
  tasks: many(tasks),
}));

export const tasksRelations = relations(tasks, ({ one }) => ({
  project: one(projects, {
    fields: [tasks.projectId],
    references: [projects.id],
  }),
}));

Egy fontos részlet, amit érdemes megjegyezni: a relációk külön vannak definiálva a tábla definícióktól. A Drizzle-ben a foreign key (adatbázis szintű) és a relation (ORM szintű) két különböző dolog. Mindkettőre szükséged van a teljes típusbiztonsághoz és a relációs lekérdezésekhez — ne hagyd ki egyiket sem.

Migrációk kezelése drizzle-kit-tel

A Drizzle Kit elemzi a sémádat és SQL migrációs fájlokat generál. Először hozd létre a konfigurációs fájlt:

// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  schema: "./src/db/schema.ts",
  out: "./src/db/migrations",
  dialect: "postgresql",
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
  strict: true,
  verbose: true,
});

A strict: true beállítás kritikus fontosságú — és ezt nem túlzásból mondom. Ez arra kényszeríti a drizzle-kit-et, hogy megerősítést kérjen, ha kétértelmű változást észlel. Például egy oszlop átnevezését egyébként törlés + hozzáadásként értelmezné, ami szép csendben adatvesztéshez vezetne. Nem vicces.

Most generáld le és futtasd a migrációkat:

# Migráció generálása a séma alapján
npx drizzle-kit generate

# Migráció alkalmazása az adatbázisra
npx drizzle-kit migrate

# Vagy fejlesztés közben: közvetlen push (migrációs fájl nélkül)
npx drizzle-kit push

A generate SQL fájlokat hoz létre a migrations mappában — ezeket mindig commitold a verziókezelőbe. A push parancs viszont fejlesztéshez remek, mivel közvetlenül alkalmazza a séma változtatásokat, migrációs fájl nélkül.

Adatlekérdezés Server Componentekben

Most jön az igazán szép rész. A Next.js App Router Server Componentjei tökéletesen illeszkednek a Drizzle ORM-hez: a komponensek a szerveren futnak, közvetlenül hozzáférnek az adatbázishoz, és a kliensre soha nem kerül ki sem a kapcsolat, sem az ORM kódja. Szóval nincs miért aggódni biztonsági szempontból.

Alapvető lekérdezés

// src/app/projects/page.tsx
import { db } from "@/db";
import { projects } from "@/db/schema";
import { desc } from "drizzle-orm";

export default async function ProjectsPage() {
  const allProjects = await db
    .select()
    .from(projects)
    .orderBy(desc(projects.createdAt));

  return (
    <main>
      <h1>Projektek</h1>
      <ul>
        {allProjects.map((project) => (
          <li key={project.id}>
            <h2>{project.name}</h2>
            <p>{project.description}</p>
          </li>
        ))}
      </ul>
    </main>
  );
}

Ugye milyen tiszta? Nincs API réteg, nincs fetch hívás — csak egy sima adatbázis lekérdezés, közvetlenül a komponensben.

Relációs lekérdezés (Drizzle Query API)

A Drizzle Query API lehetővé teszi a relációs lekérdezéseket SQL JOIN-ok nélkül. Ha használtad már a Prisma include szintaxisát, ez hasonló koncepció — csak SQL-közelibb megközelítéssel:

// src/app/projects/[id]/page.tsx
import { db } from "@/db";
import { eq } from "drizzle-orm";

interface Props {
  params: Promise<{ id: string }>;
}

export default async function ProjectDetailPage({ params }: Props) {
  const { id } = await params;

  const project = await db.query.projects.findFirst({
    where: (projects, { eq }) => eq(projects.id, parseInt(id)),
    with: {
      tasks: {
        orderBy: (tasks, { desc }) => [desc(tasks.priority)],
      },
    },
  });

  if (!project) return <p>A projekt nem található.</p>;

  return (
    <main>
      <h1>{project.name}</h1>
      <p>{project.description}</p>
      <h2>Feladatok ({project.tasks.length})</h2>
      <ul>
        {project.tasks.map((task) => (
          <li key={task.id}>
            <span>{task.completed ? "✓" : "○"}</span>
            {task.title}
          </li>
        ))}
      </ul>
    </main>
  );
}

Egy apró de lényeges dolog: ahhoz, hogy a db.query API működjön, feltétlenül add át a séma objektumot a drizzle() hívásban. E nélkül a relációs lekérdezések egyszerűen nem érhetők el, és elég rejtélyes hibaüzeneteket fogsz kapni.

CRUD műveletek Server Actionökkel

A Server Actions a Next.js beépített megoldása a szerver oldali mutációkra. A Drizzle ORM-mel kombinálva tiszta, típusbiztos CRUD műveleteket hozhatsz létre — és ami a legjobb: API végpontok nélkül.

Nézzük végig az összes alapműveletet:

// src/app/actions/tasks.ts
"use server";

import { db } from "@/db";
import { tasks } from "@/db/schema";
import { eq } from "drizzle-orm";
import { revalidatePath } from "next/cache";
import { taskSchema } from "@/lib/validators";

// CREATE — Új feladat létrehozása
export async function createTask(formData: FormData) {
  const raw = {
    title: formData.get("title") as string,
    description: formData.get("description") as string,
    projectId: Number(formData.get("projectId")),
    priority: Number(formData.get("priority") ?? 0),
  };

  const validated = taskSchema.parse(raw);

  await db.insert(tasks).values(validated);
  revalidatePath("/projects");
}

// READ — Egyedi feladat lekérdezése
export async function getTask(id: number) {
  const task = await db.query.tasks.findFirst({
    where: eq(tasks.id, id),
    with: { project: true },
  });
  return task ?? null;
}

// UPDATE — Feladat frissítése
export async function updateTask(id: number, formData: FormData) {
  const raw = {
    title: formData.get("title") as string,
    description: formData.get("description") as string,
    priority: Number(formData.get("priority") ?? 0),
  };

  await db
    .update(tasks)
    .set({
      title: raw.title,
      description: raw.description,
      priority: raw.priority,
    })
    .where(eq(tasks.id, id));

  revalidatePath("/projects");
}

// DELETE — Feladat törlése
export async function deleteTask(id: number) {
  await db.delete(tasks).where(eq(tasks.id, id));
  revalidatePath("/projects");
}

// TOGGLE — Feladat állapot váltása
export async function toggleTask(id: number) {
  const task = await db.query.tasks.findFirst({
    where: eq(tasks.id, id),
  });

  if (!task) throw new Error("Feladat nem található");

  await db
    .update(tasks)
    .set({ completed: !task.completed })
    .where(eq(tasks.id, id));

  revalidatePath("/projects");
}

Figyeld meg a revalidatePath használatát minden egyes mutáció után. Ez biztosítja, hogy a Next.js gyorsítótár frissüljön, és a felhasználó tényleg a legújabb adatokat lássa. Könnyű elfelejteni, de nélküle az UI elavult marad — ami frusztráló tud lenni.

Zod validáció integrálása

Szóval van egy Drizzle sémánk, amiből a TypeScript típusok automatikusan jönnek. De mi a helyzet a runtime validációval? Itt jön képbe a drizzle-zod csomag, ami automatikusan generál Zod sémákat a tábla definíciókból. Ezzel eliminálhatsz minden kézi szinkronizációt az adatbázis séma és a validációs szabályok között.

npm install drizzle-zod zod
// src/lib/validators.ts
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { tasks } from "@/db/schema";
import { z } from "zod";

// Automatikusan generált insert séma
// a tábla definícióból
export const taskInsertSchema = createInsertSchema(tasks, {
  title: z.string().min(1, "A cím megadása kötelező").max(255),
  description: z.string().max(1000).optional(),
  priority: z.number().int().min(0).max(5),
});

// Egyedi validációs séma űrlapokhoz
export const taskSchema = taskInsertSchema.pick({
  title: true,
  description: true,
  projectId: true,
  priority: true,
});

// Select séma a visszaadott adatokhoz
export const taskSelectSchema = createSelectSchema(tasks);

// Típus export
export type TaskInsert = z.infer<typeof taskInsertSchema>;
export type TaskSelect = z.infer<typeof taskSelectSchema>;

Az egész rendszer egyetlen forrásból táplálkozik (a Drizzle séma): az adatbázis struktúra, a TypeScript típusok és a validációs szabályok mind automatikusan szinkronban maradnak. Ha módosítod a sémát, minden más követi. Ennél szebb single source of truth-t nehéz elképzelni.

Összetett lekérdezések és tranzakciók

A valós alkalmazásokban persze ritkán van szükséged csak egyszerű CRUD-ra. Nézzük meg, hogyan kezelheted az összetettebb mintákat — mert itt mutatkozik meg igazán, hogy a Drizzle mennyire SQL-közelien gondolkodik.

Szűrés, lapozás és rendezés

import { db } from "@/db";
import { tasks } from "@/db/schema";
import { and, eq, ilike, desc, sql } from "drizzle-orm";

interface TaskFilters {
  projectId: number;
  search?: string;
  completed?: boolean;
  page?: number;
  pageSize?: number;
}

export async function getFilteredTasks(filters: TaskFilters) {
  const { projectId, search, completed, page = 1, pageSize = 20 } = filters;

  const conditions = [eq(tasks.projectId, projectId)];

  if (search) {
    conditions.push(ilike(tasks.title, `%${search}%`));
  }
  if (completed !== undefined) {
    conditions.push(eq(tasks.completed, completed));
  }

  const [data, countResult] = await Promise.all([
    db
      .select()
      .from(tasks)
      .where(and(...conditions))
      .orderBy(desc(tasks.priority), desc(tasks.createdAt))
      .limit(pageSize)
      .offset((page - 1) * pageSize),
    db
      .select({ count: sql<number>`count(*)` })
      .from(tasks)
      .where(and(...conditions)),
  ]);

  return {
    tasks: data,
    total: countResult[0].count,
    totalPages: Math.ceil(countResult[0].count / pageSize),
  };
}

Tranzakciók

Amikor több táblát érintő műveletet végzel, a tranzakciók biztosítják, hogy vagy minden sikerül, vagy semmi. Ez nem opcionális luxus — ez produkciós alapkövetelmény:

export async function createProjectWithTasks(
  projectData: { name: string; description?: string },
  taskList: { title: string; priority: number }[]
) {
  return await db.transaction(async (tx) => {
    const [newProject] = await tx
      .insert(projects)
      .values(projectData)
      .returning();

    if (taskList.length > 0) {
      await tx.insert(tasks).values(
        taskList.map((task) => ({
          ...task,
          projectId: newProject.id,
          completed: false,
        }))
      );
    }

    return newProject;
  });
}

A tranzakción belül a tx objektumot használd a db helyett — ha bármelyik művelet hibát dob, az egész tranzakció automatikusan visszagörgetődik. Egyszerű és kiszámítható.

Connection pooling szerverless környezetben

A szerverless és edge környezetek speciális kihívást jelentenek az adatbázis-kapcsolatok kezelésében. Minden függvényhívás potenciálisan új kapcsolatot nyit, ami gyorsan kimerítheti az adatbázis kapcsolatlimitjét. (Volt már részem ehhez — nem szórakoztató éjjel 2-kor debugolni.)

Neon szerverless driver

A legegyszerűbb megoldás: a Neon szerverless drivere HTTP-alapú, tehát nincs szükség hagyományos connection poolingra. Minden lekérdezés egy önálló HTTP kérés — tökéletes szerverless környezethez:

// Neon HTTP driver — nincs pool probléma
import { neon } from "@neondatabase/serverless";
import { drizzle } from "drizzle-orm/neon-http";

const sql = neon(process.env.DATABASE_URL!);
export const db = drizzle(sql, { schema });

Hagyományos PostgreSQL connection poolinggal

Ha saját PostgreSQL szervert vagy nem HTTP-alapú providert használsz, szükséged lesz connection poolingra. A leggyakoribb megoldás a PgBouncer vagy a Supabase poolere:

// Connection pooling URL-lel (pl. Supabase)
import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";

// A pooler URL-t használd, nem a közvetlen kapcsolatot
const client = postgres(process.env.DATABASE_POOLER_URL!, {
  prepare: false, // Szükséges tranzakció pooling módban
});

export const db = drizzle(client, { schema });

A prepare: false beállítás kritikus, ha PgBouncer tranzakció módban fut. A prepared statementek nem működnek ilyen konfigurációban, és a hibaüzenet sajnos nem mindig egyértelmű — szóval jobb, ha előre beállítod.

Edge Runtime kompatibilitás

A Drizzle ORM mindössze ~7,4 KB gzippelve. Összehasonlításképpen a Prisma Client ~2 MB. Ez a különbség a cold start idők szempontjából döntő a Vercel Edge Runtime vagy Cloudflare Workers környezetben. A Drizzle natívan edge-kompatibilis, nincs szükség kiegészítő szolgáltatásra (mint a Prisma Accelerate).

Produkciós best practice-ek

Összegyűjtöttem azokat a mintákat, amelyeket a valós, produkciós Next.js + Drizzle projektek során a legfontosabbnak tartok. Ezek azok a dolgok, amikről ritkán beszélnek a tutorialok, de élesben nélkülözhetetlenek.

1. Soha ne használj sql.raw()-t felhasználói inputtal

A Drizzle sql template literal automatikusan paraméterezi a lekérdezéseket — de a sql.raw() nem. Soha, de tényleg soha ne adj felhasználói inputot a sql.raw()-nak, mert SQL injection támadásnak nyitod meg az ajtót.

// HELYTELEN — SQL injection veszély!
const result = await db.execute(
  sql.raw(`SELECT * FROM tasks WHERE title = '${userInput}'`)
);

// HELYES — paraméterezett lekérdezés
const result = await db.execute(
  sql`SELECT * FROM tasks WHERE title = ${userInput}`
);

2. Használj Data Access Layer-t

Ne szórd szét a db hívásokat a komponenseidben — hosszú távon káosz lesz belőle. Inkább hozz létre egy dedikált adatelérési réteget:

// src/db/queries/tasks.ts
import { db } from "@/db";
import { tasks } from "@/db/schema";
import { eq, and, sql } from "drizzle-orm";

export const taskQueries = {
  getAll: (projectId: number) =>
    db.query.tasks.findMany({
      where: eq(tasks.projectId, projectId),
      with: { project: true },
    }),

  getById: (id: number) =>
    db.query.tasks.findFirst({
      where: eq(tasks.id, id),
    }),

  getCompletedCount: (projectId: number) =>
    db
      .select({ count: sql<number>`count(*)` })
      .from(tasks)
      .where(
        and(
          eq(tasks.projectId, projectId),
          eq(tasks.completed, true)
        )
      ),
};

3. Indexek a sémában

A Drizzle lehetővé teszi indexek definiálását közvetlenül a sémában — és érdemes is élni vele, mert így a migrációk automatikusan tartalmazzák őket:

import { pgTable, serial, varchar, integer, index } from "drizzle-orm/pg-core";

export const tasks = pgTable(
  "tasks",
  {
    id: serial("id").primaryKey(),
    title: varchar("title", { length: 255 }).notNull(),
    projectId: integer("project_id").notNull(),
    priority: integer("priority").default(0).notNull(),
  },
  (table) => [
    index("tasks_project_id_idx").on(table.projectId),
    index("tasks_priority_idx").on(table.priority),
  ]
);

4. Prepared statementek ismétlődő lekérdezésekhez

import { db } from "@/db";
import { tasks } from "@/db/schema";
import { eq, sql } from "drizzle-orm";

// Egyszer definiálva, többször felhasználva
const getTasksByProject = db
  .select()
  .from(tasks)
  .where(eq(tasks.projectId, sql.placeholder("projectId")))
  .prepare("get_tasks_by_project");

// Használat
const result = await getTasksByProject.execute({ projectId: 42 });

A prepared statementek kihagyják a lekérdezés-tervezési lépést, ami mérhető teljesítményjavulást jelent gyakran futtatott lekérdezéseknél. Nem hatalmas különbség egyenként, de összeadódik.

5. Migrációk commitolása és strict mód

Mindig commitold a generált migrációs fájlokat a verziókezelőbe, és mindig használd a strict: true beállítást a drizzle.config.ts-ben. Komolyan. A strict mód nélkül a drizzle-kit egy oszlop átnevezését törlés + hozzáadásként értelmezheti, ami adatvesztéshez vezet. Ezt a hibát elég egyszer elkövetni.

Összefoglalás

A Drizzle ORM és a Next.js App Router kombinációja 2026-ban szerintem a leghatékonyabb módja a típusbiztos, teljes stackes alkalmazások fejlesztésének. A séma TypeScriptben van, a típusok automatikusan szinkronban maradnak, a Server Components közvetlenül lekérdezik az adatbázist, a Server Actions pedig biztonságos mutációkat biztosítanak — mindezt egyetlen, koherens adatforrásból.

A Drizzle könnyűsúlyú jellege, edge-kompatibilitása és SQL-közeli szintaxisa ideálissá teszi a modern szerverless környezetekhez. Ha még nem próbáltad, ideje belevágni — a tanulási görbe meglepően rövid, különösen ha van SQL tapasztalatod.

Gyakran Ismételt Kérdések

Mikor válasszam a Drizzle ORM-et a Prisma helyett Next.js-hez?

A Drizzle-t akkor érdemes választani, ha edge vagy szerverless környezetbe deployolsz (a bundle méret lényegesen kisebb: ~7,4 KB vs ~2 MB), ha SQL-közeli szintaxist preferálsz, vagy ha nem akarsz külön kódgenerálási lépést. A Prisma viszont erősebb választás, ha a csapatod még nem jártas az SQL-ben, vagy ha szükséged van a Prisma Accelerate globális connection poolingjára.

Hogyan kezeljem a connection poolingot Drizzle ORM-mel Vercel szerverless környezetben?

A legegyszerűbb megoldás a Neon szerverless driver használata — az HTTP-alapú, szóval nincs szüksége hagyományos poolingra. Ha hagyományos PostgreSQL-t használsz, állíts be PgBouncer-t vagy használd a Supabase beépített poolerét, és ne feledkezz meg a prepare: false beállításról tranzakció pooling módban.

Biztonságos a Drizzle ORM az SQL injection ellen?

Igen. A Drizzle ORM sql template literálja automatikusan paraméterezi a lekérdezéseket, ami védelmet nyújt SQL injection ellen. Az egyetlen kivétel a sql.raw(), amelyet soha ne használj felhasználói inputtal. A query builder és az eq(), ilike() és hasonló operátorok szintén biztonságosak.

Működik a Drizzle ORM a Next.js Edge Runtime-mal?

Igen, natívan. Nincs benne natív bináris (mint a Prisma korábbi verzióiban), mindössze ~7,4 KB gzippelve, és működik Vercel Edge Runtime, Cloudflare Workers és minden más edge környezetben. A Neon vagy PlanetScale szerverless driverekkel kombinálva tökéletes edge-first adatbázis réteget kapsz.

Hogyan tartom szinkronban a Drizzle sémát, a TypeScript típusokat és a Zod validációt?

A Drizzle séma egyben a TypeScript típusok forrása is — nincs szükség külön generate lépésre. A drizzle-zod csomaggal a createInsertSchema() és createSelectSchema() függvényekkel automatikusan generálhatsz Zod validátorokat a tábla definíciókból. Egyetlen forrásból származik minden: az adatbázis struktúra, a típusok és a validáció.

A Szerzőről Tomasz Wieczorek

Tomasz is a senior frontend engineer with eleven years of experience, currently a tech lead at a Berlin-based fintech where he migrated 180 routes from CRA to Next.js 14 App Router over nine months without a single user-facing outage. Before that, four years at Klarna building the merchant dashboard in Next.js, and two years at a small agency in Krakow shipping marketing sites for European retailers. He maintains two small open-source libraries in the React ecosystem, one for typed environment variables and one for a Suspense-friendly data fetching wrapper that predates the React 19 use() hook. He prefers Drizzle over Prisma, NextAuth over Clerk for self-hosted setups, and has strong feelings about putting business logic in Server Components. He writes the kind of tutorials that show the broken intermediate state, not just the working final code.