move to drizzle instead of prisma
This commit is contained in:
14
README.md
14
README.md
@@ -4,7 +4,7 @@ Minimal Next.js web boilerplate with:
|
|||||||
|
|
||||||
- Next.js 16 Pages Router
|
- Next.js 16 Pages Router
|
||||||
- React 19
|
- React 19
|
||||||
- Prisma 7 + PostgreSQL
|
- Drizzle + PostgreSQL
|
||||||
- `@t3-oss/env-nextjs` runtime env parsing
|
- `@t3-oss/env-nextjs` runtime env parsing
|
||||||
- `oxfmt` and `oxlint`
|
- `oxfmt` and `oxlint`
|
||||||
- `vinext` for local dev and Cloudflare-targeted builds
|
- `vinext` for local dev and Cloudflare-targeted builds
|
||||||
@@ -14,7 +14,7 @@ Minimal Next.js web boilerplate with:
|
|||||||
|
|
||||||
- Node.js 24+
|
- Node.js 24+
|
||||||
- `pnpm` 10+
|
- `pnpm` 10+
|
||||||
- PostgreSQL access if you plan to run Prisma queries
|
- PostgreSQL access if you plan to run Drizzle queries
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ Create a local env file:
|
|||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
```
|
```
|
||||||
|
|
||||||
Sync the sample Prisma schema when your database is ready:
|
Sync the sample Drizzle schema when your database is ready:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm db:push
|
pnpm db:push
|
||||||
@@ -54,14 +54,14 @@ pnpm dev
|
|||||||
- `pnpm lint`: run Oxfmt checks and Oxlint
|
- `pnpm lint`: run Oxfmt checks and Oxlint
|
||||||
- `pnpm format:write`: format supported files with Oxfmt
|
- `pnpm format:write`: format supported files with Oxfmt
|
||||||
- `pnpm typecheck`: run TypeScript checks
|
- `pnpm typecheck`: run TypeScript checks
|
||||||
- `pnpm db:push`: push the Prisma schema to your database
|
- `pnpm db:push`: push the Drizzle schema to your database
|
||||||
- `pnpm db:studio`: open Prisma Studio
|
- `pnpm db:studio`: open Drizzle Studio
|
||||||
|
|
||||||
## Project layout
|
## Project layout
|
||||||
|
|
||||||
- `src/env.ts`: runtime env validation and defaults
|
- `src/env.ts`: runtime env validation and defaults
|
||||||
- `src/server/db.ts`: Prisma singleton using the Postgres adapter
|
- `src/server/db.ts`: Drizzle client using postgres-js
|
||||||
- `prisma/schema.prisma`: sample `Post` model and Prisma client generator
|
- `src/server/schema.ts`: sample `Post` table schema
|
||||||
- `wrangler.jsonc`: Cloudflare Workers runtime configuration
|
- `wrangler.jsonc`: Cloudflare Workers runtime configuration
|
||||||
|
|
||||||
## Cloudflare
|
## Cloudflare
|
||||||
|
|||||||
11
drizzle.config.ts
Normal file
11
drizzle.config.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import "dotenv/config";
|
||||||
|
import { defineConfig } from "drizzle-kit";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
schema: "./src/server/schema.ts",
|
||||||
|
out: "./drizzle",
|
||||||
|
dialect: "postgresql",
|
||||||
|
dbCredentials: {
|
||||||
|
url: process.env.DATABASE_URL ?? "",
|
||||||
|
},
|
||||||
|
});
|
||||||
12
package.json
12
package.json
@@ -18,18 +18,16 @@
|
|||||||
"format:check": "oxfmt --check .",
|
"format:check": "oxfmt --check .",
|
||||||
"format:write": "oxfmt .",
|
"format:write": "oxfmt .",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"db:push": "prisma db push",
|
"db:push": "drizzle-kit push",
|
||||||
"db:studio": "prisma studio",
|
"db:studio": "drizzle-kit studio"
|
||||||
"postinstall": "prisma generate"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/adapter-pg": "7.5.0",
|
|
||||||
"@prisma/client": "7.5.0",
|
|
||||||
"@t3-oss/env-nextjs": "^0.13.10",
|
"@t3-oss/env-nextjs": "^0.13.10",
|
||||||
"babel-plugin-react-compiler": "^1.0.0",
|
"babel-plugin-react-compiler": "^1.0.0",
|
||||||
|
"drizzle-orm": "^0.45.1",
|
||||||
"dotenv": "^17.3.1",
|
"dotenv": "^17.3.1",
|
||||||
"next": "^16.2.0",
|
"next": "^16.2.0",
|
||||||
"pg": "^8.20.0",
|
"postgres": "^3.4.7",
|
||||||
"react": "^19.2.4",
|
"react": "^19.2.4",
|
||||||
"react-dom": "^19.2.4",
|
"react-dom": "^19.2.4",
|
||||||
"zod": "^4.3.6"
|
"zod": "^4.3.6"
|
||||||
@@ -40,9 +38,9 @@
|
|||||||
"@types/react": "^19.2.14",
|
"@types/react": "^19.2.14",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@vitejs/plugin-react": "^6.0.1",
|
"@vitejs/plugin-react": "^6.0.1",
|
||||||
|
"drizzle-kit": "^0.31.8",
|
||||||
"oxfmt": "^0.41.0",
|
"oxfmt": "^0.41.0",
|
||||||
"oxlint": "^1.56.0",
|
"oxlint": "^1.56.0",
|
||||||
"prisma": "^7.5.0",
|
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"vinext": "0.0.32",
|
"vinext": "0.0.32",
|
||||||
"vite": "^8.0.1",
|
"vite": "^8.0.1",
|
||||||
|
|||||||
1559
pnpm-lock.yaml
generated
1559
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,5 @@
|
|||||||
onlyBuiltDependencies:
|
onlyBuiltDependencies:
|
||||||
- "@prisma/engines"
|
|
||||||
- esbuild
|
- esbuild
|
||||||
- prisma
|
|
||||||
- sharp
|
- sharp
|
||||||
- workerd
|
- workerd
|
||||||
- wrangler
|
- wrangler
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
import "dotenv/config";
|
|
||||||
import { defineConfig } from "prisma/config";
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
schema: "prisma/schema.prisma",
|
|
||||||
datasource: {
|
|
||||||
url: process.env.DATABASE_URL,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
generator client {
|
|
||||||
provider = "prisma-client"
|
|
||||||
output = "../generated/prisma"
|
|
||||||
|
|
||||||
moduleFormat = "esm"
|
|
||||||
generatedFileExtension = "ts"
|
|
||||||
importFileExtension = "ts"
|
|
||||||
engineType = "client"
|
|
||||||
}
|
|
||||||
|
|
||||||
datasource db {
|
|
||||||
provider = "postgresql"
|
|
||||||
}
|
|
||||||
|
|
||||||
model Post {
|
|
||||||
id String @id @default(cuid())
|
|
||||||
title String
|
|
||||||
slug String @unique
|
|
||||||
body String?
|
|
||||||
published Boolean @default(false)
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
|
|
||||||
@@index([published, createdAt])
|
|
||||||
}
|
|
||||||
8
src/pages/api/posts.ts
Normal file
8
src/pages/api/posts.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
import { listRecentPosts } from "~/server/posts";
|
||||||
|
|
||||||
|
export default async function handler(_request: NextApiRequest, response: NextApiResponse) {
|
||||||
|
const posts = await listRecentPosts();
|
||||||
|
|
||||||
|
response.status(200).json({ posts });
|
||||||
|
}
|
||||||
@@ -13,11 +13,11 @@ export default function HomePage() {
|
|||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
<title>Vinext Boilerplate</title>
|
<title>Vinext Boilerplate</title>
|
||||||
<meta content={"Minimal Next.js, Prisma, Oxc, Vinext, and Wrangler starter."} name={"description"} />
|
<meta content={"Minimal Next.js, Drizzle, Oxc, Vinext, and Wrangler starter."} name={"description"} />
|
||||||
</Head>
|
</Head>
|
||||||
<main className={"page-shell"}>
|
<main className={"page-shell"}>
|
||||||
<section className={"hero-card"}>
|
<section className={"hero-card"}>
|
||||||
<p className={"eyebrow"}>Next.js + Prisma + Cloudflare</p>
|
<p className={"eyebrow"}>Next.js + Drizzle + Cloudflare</p>
|
||||||
<h1>Vinext Boilerplate</h1>
|
<h1>Vinext Boilerplate</h1>
|
||||||
<p className={"lead"}>
|
<p className={"lead"}>
|
||||||
Minimal Pages Router starter built for local web development first and Cloudflare Workers deployment second.
|
Minimal Pages Router starter built for local web development first and Cloudflare Workers deployment second.
|
||||||
@@ -25,7 +25,7 @@ export default function HomePage() {
|
|||||||
<div className={"chip-row"}>
|
<div className={"chip-row"}>
|
||||||
<span className={"chip"}>Next 16</span>
|
<span className={"chip"}>Next 16</span>
|
||||||
<span className={"chip"}>React 19</span>
|
<span className={"chip"}>React 19</span>
|
||||||
<span className={"chip"}>Prisma 7</span>
|
<span className={"chip"}>Drizzle</span>
|
||||||
<span className={"chip"}>vinext</span>
|
<span className={"chip"}>vinext</span>
|
||||||
<span className={"chip"}>wrangler</span>
|
<span className={"chip"}>wrangler</span>
|
||||||
<span className={"chip"}>oxfmt + oxlint</span>
|
<span className={"chip"}>oxfmt + oxlint</span>
|
||||||
|
|||||||
@@ -1,23 +1,22 @@
|
|||||||
import { PrismaClient } from "@/db";
|
import { drizzle } from "drizzle-orm/postgres-js";
|
||||||
import { PrismaPg } from "@prisma/adapter-pg";
|
import postgres from "postgres";
|
||||||
import { env } from "~/env";
|
import { env } from "~/env";
|
||||||
|
import * as schema from "~/server/schema";
|
||||||
|
|
||||||
const adapter = new PrismaPg({
|
const createDb = () => {
|
||||||
connectionString: env.DATABASE_URL,
|
const client = postgres(env.DATABASE_URL, {
|
||||||
|
prepare: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const createPrismaClient = () =>
|
return drizzle(client, { schema });
|
||||||
new PrismaClient({
|
|
||||||
adapter,
|
|
||||||
log: env.NODE_ENV === "development" ? ["error", "warn"] : ["error"],
|
|
||||||
});
|
|
||||||
|
|
||||||
const globalForPrisma = globalThis as unknown as {
|
|
||||||
prisma: ReturnType<typeof createPrismaClient> | undefined;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const db = globalForPrisma.prisma ?? createPrismaClient();
|
const globalForDb = globalThis as unknown as {
|
||||||
|
db: ReturnType<typeof createDb> | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const db = globalForDb.db ?? createDb();
|
||||||
|
|
||||||
if (env.NODE_ENV !== "production") {
|
if (env.NODE_ENV !== "production") {
|
||||||
globalForPrisma.prisma = db;
|
globalForDb.db = db;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
|
import { desc } from "drizzle-orm";
|
||||||
import { db } from "~/server/db";
|
import { db } from "~/server/db";
|
||||||
|
import { posts } from "~/server/schema";
|
||||||
|
|
||||||
export const listRecentPosts = async (limit: number = 5) =>
|
export const listRecentPosts = async (limit: number = 5) =>
|
||||||
db.post.findMany({
|
db.select().from(posts).orderBy(desc(posts.createdAt)).limit(limit);
|
||||||
take: limit,
|
|
||||||
orderBy: {
|
|
||||||
createdAt: "desc",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|||||||
22
src/server/schema.ts
Normal file
22
src/server/schema.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { index, pgTable, text, timestamp, boolean } from "drizzle-orm/pg-core";
|
||||||
|
|
||||||
|
export const posts = pgTable(
|
||||||
|
"posts",
|
||||||
|
{
|
||||||
|
id: text("id")
|
||||||
|
.primaryKey()
|
||||||
|
.$defaultFn(() => crypto.randomUUID()),
|
||||||
|
title: text("title").notNull(),
|
||||||
|
slug: text("slug").notNull().unique(),
|
||||||
|
body: text("body"),
|
||||||
|
published: boolean("published").notNull().default(false),
|
||||||
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
||||||
|
updatedAt: timestamp("updated_at", { withTimezone: true })
|
||||||
|
.notNull()
|
||||||
|
.defaultNow()
|
||||||
|
.$onUpdate(() => new Date()),
|
||||||
|
},
|
||||||
|
(table) => ({
|
||||||
|
publishedCreatedAtIdx: index("posts_published_created_at_idx").on(table.published, table.createdAt),
|
||||||
|
}),
|
||||||
|
);
|
||||||
@@ -23,8 +23,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"~/*": ["./src/*"],
|
"~/*": ["./src/*"]
|
||||||
"@/db": ["./generated/prisma/client"]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
|
|||||||
Reference in New Issue
Block a user