The Next.js Prisma app from an AI builder: schema, migrations and seed
When you download an Anticode build as a Next.js project, its data layer is plain Prisma 6 on Postgres: one schema file, two SQL migrations and a seed script. Nothing is hidden behind an Anticode service. If you want a nextjs Prisma app from AI builder output that a developer can read in ten minutes, this is what each file holds and the order to run things in.
What's in prisma/
| File | Contents |
|---|---|
schema.prisma | A postgresql datasource reading DATABASE_URL, a Role enum and eight models |
migrations/0001_init | The tables, indexes and foreign keys, generated with prisma migrate diff |
migrations/0002_row_level_security | Hand-written SQL that enables and forces row-level security on every table, with policies per role |
seed.ts | Creates or resets the first owner from OWNER_EMAIL and OWNER_PASSWORD |
The models are Booking, Message and Subscriber for the three public forms; User, Session and LoginToken for accounts; RateLimit for the forms' limits; and AuditLog. Ids are UUIDs, and the comments in the schema point at the security choices, such as two-factor secrets being stored encrypted and sessions keyed by a SHA-256 hash of the cookie.
The commands, in order
package.json wraps the Prisma CLI in npm scripts. After npm install and filling in .env from .env.example:
npm run db:migraterunsprisma migrate dev. It applies both migrations, generates the client, and is meant for a development database.npm run db:seedrunsprisma/seed.tswith tsx. It needs OWNER_EMAIL to be a valid address and OWNER_PASSWORD to be at least 12 characters, and prints "Owner ready" when done. Remove the password from your environment afterwards.npm run devstarts Next.js. Sign in at/admin/loginand set up two-factor sign-in on first visit.- In production,
npm run db:deploy(prisma migrate deploy) applies pending migrations, andnpm run buildrunsprisma generatebeforenext build. On Vercel the README suggestsnpm run db:deploy && npm run buildas the build command.
migrate dev or migrate deploy on a hosted database?
Prisma's documentation on the shadow database explains that migrate dev creates and deletes a temporary second database each time it runs, to detect drift, and that hosts which don't allow creating databases need one configured by hand. migrate deploy doesn't use a shadow database at all. So if npm run db:migrate fails against a cloud database with a permissions error, run npm run db:deploy instead: on an empty database it applies the same two migrations. Keep migrate dev for when you change the schema yourself, ideally against a local or branch database.
Adding a field
Say the booking form needs a "notes" field. Three places change, and the README lists them:
- the form in
components/sections/Book.tsx, with a new input named notes; - the Zod schema in
lib/validate.ts, so the route accepts it and caps its length; - the Booking model in
prisma/schema.prisma, asnotes String?.
Then run npx prisma migrate dev --name booking-notes to create a third migration. Because row-level security is set per table, a new column needs no new policy; a new table does, or no role can read it once it's forced. Copy the pattern from migration 0002. The export's tests include a guardrail that fails if any table is missing row-level security, so npm test will remind you.
Why the queries run inside transactions
Pages and routes don't call prisma.booking.findMany() directly. They go through asRole(role, fn) in lib/db.ts, which opens a transaction, sets app.role (and app.email for customers) with set_config(…, true), then runs your queries. The settings last only for that transaction, so they don't leak to the next request even when connections are pooled. If you add a page, follow the same pattern; a query outside asRole has no role set and the policies return nothing.
Limits of the template
- Pinned to Prisma 6. The README asks you to treat 7 as a deliberate upgrade, because its configuration format changed, and to follow Prisma's upgrade guide.
- One database URL. The datasource reads
DATABASE_URLonly. If your host wants a separate direct URL for migrations, adddirectUrlyourself; see the Neon and Supabase notes. - No payments, products or orders models. Add them if the app needs to sell.
- A one-way copy. Changes here never flow back to the Anticode builder.
For the database design and the role check that matters on hosted Postgres, see Postgres in the export. The wider tour is on the Next.js export page.
Questions people ask
Do I have to use Prisma?
The template is built on it: routes, seed and tests all use the Prisma client. Replacing it is possible but means rewriting lib/db.ts and every query.
What does re-running the seed do?
It upserts: the owner's email is kept and the password and OWNER role are reset to the values in your environment.
Is Zod used for the database too?
Zod validates request input in lib/validate.ts before Prisma writes it. Prisma's own types cover the database side.