Skip to content
Open
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
---
title: "Prisma Next Early Access: Write Your Contract, Prompt Your Agent, Ship Your App"
slug: "prisma-next-early-access-write-your-contract-prompt-your-agent-ship-your-app"
date: "2026-05-18"
authors:
- "Ankur Datta"
- "Will Madden"
metaTitle: "Prisma Next Early Access: Write Your Contract, Prompt Your Agent, Ship Your App"
metaDescription: "Prisma Next is open for Early Access. Define your data layer as a contract and the framework handles migrations, type-safe queries, and continuous upgrades — safe to delegate to your agent."
heroImagePath: "/prisma-next-early-access-write-your-contract-prompt-your-agent-ship-your-app/imgs/meta.png"
heroImageAlt: "Prisma Next Early Access"
metaImagePath: "/prisma-next-early-access-write-your-contract-prompt-your-agent-ship-your-app/imgs/meta.png"
tags:
- "orm"
- "announcement"
- "ai"
---

**Prisma Next gives you superpowers, and makes it safe to delegate them to your agent, leaving you to focus on what matters: your app.** Define your data layer as a contract and the framework handles everything else for you: migrating your DB, type-checking your queries, meaningful errors when something goes wrong.

Agents are here to stay. They don't replace you, they multiply your capabilities. From your first touch to your first paying user, Prisma Next's _agent DX_ keeps your agent in the loop and on track. Instant onboarding, guardrails, verifiable type-checked work, and continuous upgrades.

Today, **Prisma Next is open for Early Access for Postgres and [MongoDB](https://www.prisma.io/blog/mongodb-without-compromise).**

## One-line setup and onboarding without any learning curve

If you've ever picked up a new framework, you know how long it takes to climb a steep learning curve. You read the docs, build a toy project and make mistakes the docs warned you about. It takes weeks to absorb the framework's idioms until you're confident enough to actually build.

When you install Prisma Next, it comes with a family of agent skills that make your agent an instant expert.

You can quickly set up Prisma Next along with the skills and template of your choice by running:

```bash
npm create prisma@next
```

The learning curve disappears and you can start working on something meaningful straight away. Watch how your agent uses the framework and you'll learn it as you go and if you have a question, ask your agent. It knows the answer.

## Write your contract, we handle the rest
Comment thread
ankur-arch marked this conversation as resolved.

Imagine this as your data contract (if you’re already using Prisma ORM, this is your schema.prisma):

```prisma
// contract.prisma
model Book {
id String @id @default(uuid())
title String
author String
addedAt DateTime @default(now())
}
```

It's easy to read, easy to update, and it's the single source of truth for everything in your database. Queries are type-checked against it, autocomplete reads from it, and when you change it, Prisma Next plans the migrations to match. Prisma Next handles the difficult, mechanical tasks (like migrations) so you and your agent can stay focused on your application.

## Build fast with type-safe queries and tight feedback loops

When you're building, you know what you want, you try something, see if it works, and repeat. How fast you iterate determines how fast you ship.

Your agent runs the same loop, only its feedback comes from the contract, the type checker, the structured errors, and the query builder.

Considering the book table in the contract above, you can ask the agent for a feature _"add an author table with a name and bio, and link authors to books"_ and it updates the contract:

<AutoplayYoutubeEmbed
videoId="0pvlcmFnWSI"
title="Agent updates the contract to add an author table linked to books"
/>

Then, when you ask the agent to write a query, it iterates against those guardrails inside its own tool calls until the query type-checks. Here's what that looks like in practice:

<AutoplayYoutubeEmbed
videoId="C6exOjUIgBo"
title="Agent iterates a query against the contract until it type-checks"
/>

The agent produces the correct query based on the contract:

```typescript
const books = await db.orm.Book.where((b) => b.addedAt.gte(oneWeekAgo))
.include("author", (author) => author)
.orderBy((b) => b.addedAt.desc())
.all();
```

You don't need to read every query the agent writes as the type checker already did.

## Never write a migration again

If you've ever deployed an app, you've worked with migrations. Migrations are _one of the most painful parts_ of working with a database.

You spend time getting the syntax right. Then you spend more time debugging when things go sideways. And if a migration breaks during deployment, you spend even more time fixing it in production.

In Prisma Next, instead of asking your agent to write a SQL migration (where it has all the power and a language that lends itself to simple, catastrophic mistakes) you ask it for a feature: _"Add a `published_at` field to the Book model so I can sort by when each book was published."_

<AutoplayYoutubeEmbed
videoId="2hPXEmALezI"
title="Agent edits the contract and the framework plans the migration"
/>

The agent edits the contract to add one field. Then it asks the framework to plan the migration using:

```bash
prisma-next migration plan
```

The framework produces a real, reviewable [TypeScript migration file](https://www.prisma.io/blog/typescript-migrations-in-prisma-next):

```typescript
// migrations/20260515T0900_add_book_published_at/migration.ts
export default class M extends Migration {
operations() {
return [
addColumn("public", "Book", {
name: "publishedAt",
typeSql: "timestamptz",
defaultSql: "",
nullable: true,
}),
];
}
}
```

You read it and trusted it. Your agent didn't write this; the framework did. Then you apply it to the database:

```bash
prisma-next migration apply
```

Each operation is verified before and after it executes. The whole migration runs in a single transaction so that if any step fails, the migration is rolled back and the database stays exactly as it was. Those guardrails make migrations safe for you, and that's what makes them safe to delegate to your agent.

When you need to transform data as well as change your schema, write a [data migration](https://www.prisma.io/blog/data-migrations-in-prisma-next) using the same type-safe SQL query builder available in your application, with the same type-checking and safeguards.

The agent's job is to translate your intent into a contract edit. Everything else is the framework's job. **You never write a migration and neither does your agent.**

## No more migration conflicts on parallel branches

Have you ever written a migration on one branch only to have someone else's migration merge to `main` while you're still working?

Now the migrations are out of order, your migration can't be applied, and you have to redo it before you can merge. Or disable safety checks and hope.

Prisma Next treats migration history the same way git treats code history: each migration moves your contract from one state to the next, just like each commit moves your code from one state to the next.

When two branches add migrations from the same starting point, you get the same diamond shape git shows you in `git log --graph`. The CLI can render that graph for you, and the framework knows how to walk it.

Whenever you work with people on multiple branches, this is bound to happen. When you have multiple agents working in multiple worktrees or branches, it happens even more often.

![prisma-next migration status --graph rendering a diamond migration graph](/prisma-next-early-access-write-your-contract-prompt-your-agent-ship-your-app/imgs/migration-graph.png)

> `prisma-next migration status --graph` rendering a diamond. Two branches each added a migration from the same starting point; both got merged back into `main`; the framework knows what order they need to apply in.

The `prisma-next-migration-review` skill teaches your agents to understand this graph. When a new migration reaches `main` while your agent's mid-feature, the agent reads the graph, rebases its branch, and re-runs `migration plan`. The framework re-plans the migration against the new `main`.

That's the same flow the agent ran the first time, just against the updated `main`. The migration that comes out fits on top cleanly. No special procedure to learn, no human in the middle, no `--force` with fingers crossed. Run as many features in parallel as you have agents for them.

## Ship every day with confidence

You built a feature with an agent. But how do you know it's correct? Like any other change, it needs a thorough review, and that's only possible if you can understand the changes.

Prisma Next answers that with evidence, not promises.

**Every artifact the framework produces is reviewable on disk.** The migration file is real TypeScript.

The contract diff is in git and your PR shows what changed; reviewers can read it and reviewing automation can read it too. The same surface that makes migrations easy for humans to review makes them easy for an automated reviewer agent to scan for the things you care about.

![Reviewable migration artifacts shown alongside the contract diff](/prisma-next-early-access-write-your-contract-prompt-your-agent-ship-your-app/imgs/migration-review.png)

**Check your work in CI.** Every migration is checked against the target environment before it deploys. If the production database isn't in the shape the migration expects, CI says so.

![CI checking the migration against the target environment before deploy](/prisma-next-early-access-write-your-contract-prompt-your-agent-ship-your-app/imgs/ci-check.png)

You know exactly when and why a migration will fail before it touches production. No surprise drift. No half-applied state.

**You always know which contract version each environment is on.** Prisma Next records the current contract hash directly in your database and updates it as migrations run.

A single check tells you whether the version of the app you want to deploy matches the version of the database in production. Drift between contract and database gets caught the moment it appears, not three weeks into production traffic.

The contract lets you be explicit about what each version of your app depends on.

## Continuous upgrades via per-release recipes for your agent

When a new version lands, tell your agent to _"upgrade prisma next"_.

<AutoplayYoutubeEmbed
videoId="znI2RiXJtRc"
title="Continuous upgrades via per-release recipes for your agent"
/>

Prisma Next is in Early Access and we're shipping every day, including breaking changes. To stay up to date, we ship a dedicated skill to your agent with instructions for every breaking change.

The `@prisma-next/upgrade-skill` is a versioned table of _upgrade recipes_: one per `(from-minor, to-minor)` transition, each recipe a markdown file of agent instructions plus colocated codemods and scripts where needed.

**We write the recipes**; we own the responsibility for telling your agent how to translate your code across each transition.

And this communication goes both ways: **we want your feedback, and your agent knows how to get it to us**.

If you find a bug, or something you feel is missing, ask your agent to tell us about it: _"this is a bug"_ or _"this should be a feature"_ or _"how should I do X?"_.

Your agent will pick the appropriate channel (GitHub for bugs and concrete feature requests, Discord for design questions and team Q&A), draft a structured, public-safe report, and file it on your behalf with your confirmation.

EA is collaborative, both directions. Forward via the upgrade skill and backward via the feedback skill, with your agent being the facilitator.

## Try it out

With Prisma Next, we bring **Prisma's world-class DX to your agent**. In every step from onboarding to upgrade, the framework gives you superpowers, your agent multiplies them and you focus on building your app.

Drive it yourself, let your agent drive, or hand off mid-flow. Your workflow is up to you, and with Prisma Next you can delegate with confidence.

**Try it today in a fresh new project:**

```bash
npm create prisma@next
```

Or in a test branch of an existing project:

```bash
npx prisma-next@latest init
Comment thread
ankur-arch marked this conversation as resolved.
```

Then ask your agent to build something:

> _"Build me a small app that tracks the books I'm reading. Add a few records, and show me the list."_

When you've got something running, tag [us on X](https://pris.ly/x) and tell us what you built. The best community builds get a shout-out from the Prisma account and a link in the [Prisma Next README](https://github.com/prisma/prisma-next).

And when you're ready to put it online, our hosted database [Prisma Postgres](https://www.prisma.io/postgres) has a generous free tier.

Star and watch [prisma/prisma-next](https://github.com/prisma/prisma-next) on GitHub to follow what ships next.

If you hit a snag, start a thread in [#prisma-next](https://pris.ly/discord) on [our Discord](https://pris.ly/discord).

We can't wait to see what you create.

> _Note that Prisma Next is not production-ready yet. Prisma 7 is still the right choice for production applications today. When Prisma Next is ready for general use, it will become Prisma 8._
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
89 changes: 89 additions & 0 deletions apps/blog/src/components/AutoplayYoutubeEmbed.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"use client";

import { useEffect, useRef, useState } from "react";

type Props = {
videoId: string;
title: string;
};

export const AutoplayYoutubeEmbed = ({ videoId, title }: Props) => {
const iframeRef = useRef<HTMLIFrameElement>(null);
const [playing, setPlaying] = useState(false);

useEffect(() => {
const onMessage = (event: MessageEvent) => {
if (event.source !== iframeRef.current?.contentWindow) return;
try {
const data =
typeof event.data === "string" ? JSON.parse(event.data) : event.data;
if (data?.event === "onStateChange" && data?.info === 1) {
setPlaying(true);
}
} catch {
// Non-JSON messages from the iframe are ignored.
}
};
window.addEventListener("message", onMessage);
return () => window.removeEventListener("message", onMessage);
}, []);

const onLoad = () => {
const win = iframeRef.current?.contentWindow;
if (!win) return;
win.postMessage(JSON.stringify({ event: "listening", id: videoId }), "*");
win.postMessage(
JSON.stringify({
event: "command",
func: "addEventListener",
args: ["onStateChange"],
}),
"*",
);
};

const src = `https://www.youtube.com/embed/${videoId}?enablejsapi=1&autoplay=1&mute=1&loop=1&playlist=${videoId}&controls=0&modestbranding=1&rel=0&showinfo=0&disablekb=1&fs=0&iv_load_policy=3&playsinline=1`;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove accessibility barriers to user control.

The iframe URL disables all user interaction (controls=0, disablekb=1, fs=0), and line 69 adds pointerEvents: "none". This completely prevents users from pausing, seeking, or controlling the video, violating WCAG 2.2.2 (Pause, Stop, Hide).

Users must be able to control auto-playing content—especially instructional demonstrations where they may need to pause and review specific steps.

♿ Proposed fix to restore user control
-  const src = `https://www.youtube.com/embed/${videoId}?enablejsapi=1&autoplay=1&mute=1&loop=1&playlist=${videoId}&controls=0&modestbranding=1&rel=0&showinfo=0&disablekb=1&fs=0&iv_load_policy=3&playsinline=1`;
+  const src = `https://www.youtube.com/embed/${videoId}?enablejsapi=1&autoplay=1&mute=1&loop=1&playlist=${videoId}&controls=1&modestbranding=1&rel=0&showinfo=0&iv_load_policy=3&playsinline=1`;

And remove pointer-events blocking:

         style={{
           position: "absolute",
           inset: 0,
           width: "100%",
           height: "100%",
           border: 0,
-          pointerEvents: "none",
         }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const src = `https://www.youtube.com/embed/${videoId}?enablejsapi=1&autoplay=1&mute=1&loop=1&playlist=${videoId}&controls=0&modestbranding=1&rel=0&showinfo=0&disablekb=1&fs=0&iv_load_policy=3&playsinline=1`;
const src = `https://www.youtube.com/embed/${videoId}?enablejsapi=1&autoplay=1&mute=1&loop=1&playlist=${videoId}&controls=1&modestbranding=1&rel=0&showinfo=0&iv_load_policy=3&playsinline=1`;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/blog/src/components/AutoplayYoutubeEmbed.tsx` at line 45, The iframe in
AutoplayYoutubeEmbed builds a src string that disables user controls (const src)
and the component also sets pointerEvents: "none", preventing any interaction
and violating WCAG Pause/Stop; update the src in AutoplayYoutubeEmbed to allow
user control by removing or changing the query params that block interaction
(remove controls=0, disablekb=1, fs=0 and keep controls=1 and keyboard enabled)
and remove the pointerEvents: "none" style so users can click, pause, seek, and
use keyboard controls; ensure autoplay can remain muted if desired but the embed
must permit user interaction (adjust playlist/loop params as needed to preserve
looping without disabling controls).


return (
<div
style={{
position: "relative",
width: "100%",
aspectRatio: "16 / 9",
overflow: "hidden",
}}
>
<iframe
ref={iframeRef}
src={src}
title={title}
onLoad={onLoad}
loading="lazy"
allow="autoplay; encrypted-media; picture-in-picture"
style={{
position: "absolute",
inset: 0,
width: "100%",
height: "100%",
border: 0,
pointerEvents: "none",
}}
/>
<img
src={`https://img.youtube.com/vi/${videoId}/maxresdefault.jpg`}
alt=""
aria-hidden="true"
style={{
position: "absolute",
inset: 0,
width: "100%",
height: "100%",
objectFit: "cover",
pointerEvents: "none",
opacity: playing ? 0 : 1,
transition: "opacity 0.3s ease-in",
}}
/>
</div>
);
};
5 changes: 5 additions & 0 deletions apps/blog/src/mdx-components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { Youtube } from "@prisma-docs/ui/components/youtube";
import { TweetEmbedComp } from "@/components/TweetEmbed";
import { Meetup, MeetupList } from "@/components/Meetup";
import { Employee } from "@/components/Employee";
import { AutoplayYoutubeEmbed } from "@/components/AutoplayYoutubeEmbed";
import { withBlogBasePath, withBlogBasePathForImageSrc } from "@/lib/url";
export function getMDXComponents(components?: MDXComponents): MDXComponents {
const mdxComponents = {
Expand Down Expand Up @@ -58,11 +59,15 @@ export function getMDXComponents(components?: MDXComponents): MDXComponents {
Meetup,
MeetupList,
Employee,
AutoplayYoutubeEmbed,
Steps,
Step,
img: (props: any) => (
<ImageZoom {...(props as any)} src={withBlogBasePathForImageSrc((props as any).src)} />
),
video: (props: any) => (
<video {...(props as any)} src={withBlogBasePathForImageSrc((props as any).src)} />
),
};

return {
Expand Down
Loading