Introduction
I've built over 10 projects in 2026 using different stacks — some with Prisma, some with Supabase, some with NextAuth. After all of that, I keep coming back to the same combination: Next.js 15 + Drizzle ORM + Neon Postgres + Clerk. THis blog is fetched from
Here's why this stack works so well — and how to set it up from scratch.
Why this stack?
Next.js 15 — Server Components, Server Actions, and Edge Runtime. The most complete React framework in 2026.
Drizzle ORM — Lightweight, type-safe, and SQL-first. Faster than Prisma, simpler than raw SQL.
Neon Postgres — Serverless PostgreSQL with a generous free tier, branching, and connection pooling built in.
Clerk — Drop-in auth with pre-built UI components, social logins, and webhooks. No more rolling your own auth.
Step 1: Create the Next.js project
npx create-next-app@latest my-app --typescript --tailwind --app
cd my-app
Step 2: Set up Neon + Drizzle
npm install drizzle-orm @neondatabase/serverless
npm install -D drizzle-kit
Create src/db/schema.ts:
import { pgTable, serial, text, timestamp } from "drizzle-orm/pg-core";
export const users = pgTable("users", {
id: serial("id").primaryKey(),
clerkId: text("clerk_id").notNull().unique(),
email: text("email").notNull(),
name: text("name"),
createdAt: timestamp("created_at").defaultNow(),
});
Create 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 });
Step 3: Add Drizzle config and push schema
Create drizzle.config.ts:
import { defineConfig } from "drizzle-kit";
export default defineConfig({
schema: "./src/db/schema.ts",
out: "./drizzle",
dialect: "postgresql",
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});
npx drizzle-kit push
Step 4: Set up Clerk authentication
npm install @clerk/nextjs
Wrap your app in app/layout.tsx:
import { ClerkProvider } from "@clerk/nextjs";
export default function RootLayout({ children }) {
return (
{children}
);
}
Add Clerk keys to .env.local:
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_...
CLERK_SECRET_KEY=sk_...
Protect routes in middleware.ts:
import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server";
const isProtected = createRouteMatcher(["/dashboard(.*)"]);
export default clerkMiddleware((auth, req) => {
if (isProtected(req)) auth().protect();
});
export const config = { matcher: ["/((?!.*\\..*|_next).*)", "/"] };
Step 5: Query the database in a Server Component
import { db } from "@/db";
import { users } from "@/db/schema";
import { auth } from "@clerk/nextjs/server";
export default async function Dashboard() {
const { userId } = auth();
const user = await db.query.users.findFirst({
where: (users, { eq }) => eq(users.clerkId, userId!),
});
return
Welcome, {user?.name}
;
}
Conclusion
Next.js + Drizzle + Neon + Clerk is the stack I recommend to every developer starting a new project in 2026. It's fast to set up, type-safe end-to-end, scales to production without config changes, and has a generous free tier across every service. Stop spending a week on boilerplate — get this stack running in an afternoon and focus on building.

Top comments (0)