|
| 1 | +--- |
| 2 | +title: "See Your Migration History in Prisma Studio" |
| 3 | +slug: "prisma-studio-migrations-view" |
| 4 | +date: "2026-07-17" |
| 5 | +authors: |
| 6 | + - "Ankur Datta" |
| 7 | + - "SΓΈren Bramer Schmidt" |
| 8 | +metaTitle: "Prisma Studio Migrations View: See Your Migration History" |
| 9 | +metaDescription: "The Prisma Studio Migrations view shows every applied Prisma Next migration as a timeline with a visual diff, the executed SQL, and a schema diff." |
| 10 | +heroImagePath: "/prisma-studio-migrations-view/imgs/hero.svg" |
| 11 | +metaImagePath: "/prisma-studio-migrations-view/imgs/meta.png" |
| 12 | +heroImageAlt: "The Prisma Studio Migrations view: a timeline of applied migrations beside a visual diff canvas" |
| 13 | +tags: |
| 14 | + - "announcement" |
| 15 | + - "orm" |
| 16 | +series: prisma-next |
| 17 | +seriesIndex: 10 |
| 18 | +--- |
| 19 | + |
| 20 | +The Migrations view is a new screen in Prisma Studio, the database GUI bundled with the Prisma CLI. It shows the migration history of a [Prisma Next](https://www.prisma.io/docs/orm/next) database as a timeline: one entry per applied migration, with a visual diff of what changed, the SQL that ran, and a schema diff. |
| 21 | + |
| 22 | +Studio reads that history from the database itself, not from your repo. So it works for any Prisma Next Postgres database you can connect to, including one you have never migrated yourself. The full setup is documented in [Studio with Prisma Next](https://www.prisma.io/docs/studio/prisma-next). |
| 23 | + |
| 24 | +This is the tenth post in the Prisma Next series. The migration model it builds on is the subject of [Rethinking Database Migrations](/rethinking-database-migrations), and the files it visualizes are the ones [TypeScript Migrations in Prisma Next](/typescript-migrations-in-prisma-next) walks through. |
| 25 | + |
| 26 | + |
| 27 | + |
| 28 | +## What did that migration actually do? |
| 29 | + |
| 30 | +A migration named `add_roles_and_publishing` ran against staging three weeks ago. Now you need to know what it did. |
| 31 | + |
| 32 | +You can read the migration file, which tells you what was *supposed* to happen. You can diff two schema files and reconstruct the change in your head. You can open a SQL console and inspect the current table, which tells you where you ended up but not how you got there. Or you can ask the person who wrote it. |
| 33 | + |
| 34 | +None of these tell you what is actually applied to the database in front of you. A repo tells you what exists, not what ran. Staging may be three merges behind or one hotfix ahead. |
| 35 | + |
| 36 | +## What the Migrations view shows |
| 37 | + |
| 38 | +The record of what actually ran lives in the database. Prisma Next writes it there on every apply, and Studio reads it back. |
| 39 | + |
| 40 | +The list runs newest-first, one entry per applied migration. A β οΈ marker flags any migration carrying a destructive change, so a dropped column is visible before you click anything. |
| 41 | + |
| 42 | +Selecting a migration draws the schema at that moment: models the migration added in green, models whose table changed in amber, untouched neighbors dimmed for context. |
| 43 | + |
| 44 | +Amber means one specific thing: *this table's DDL changed*. A model that only gained a back-relation, where the foreign key lives on the other table, stays dimmed. The new relation edge is emphasized instead. If a card is amber, DDL ran against that table. |
| 45 | + |
| 46 | +## A walkthrough you can run |
| 47 | + |
| 48 | +Here is the workflow, from an empty directory. The screenshots in this post come from a six-migration history built exactly this way; the two migrations below are its first two. |
| 49 | + |
| 50 | +### Step 1: Create a project |
| 51 | + |
| 52 | +```bash |
| 53 | +npm create prisma@next |
| 54 | +``` |
| 55 | + |
| 56 | +Answer the prompts (PostgreSQL, PSL, and yes to [Prisma Postgres](https://www.prisma.io/docs/postgres)) or skip them: |
| 57 | + |
| 58 | +```bash |
| 59 | +npm create prisma@next -- my-app --yes --provider postgres --authoring psl \ |
| 60 | + --template minimal --prisma-postgres --install --emit |
| 61 | +``` |
| 62 | + |
| 63 | +This provisions a database, writes `DATABASE_URL` into `.env`, and scaffolds a contract at `src/prisma/contract.prisma`. The database is temporary for 24 hours; `.env` also holds a `CLAIM_URL` to keep it. |
| 64 | + |
| 65 | +### Step 2: Model, plan, apply |
| 66 | + |
| 67 | +Prisma Next calls your schema a [contract](https://www.prisma.io/docs/orm/next/contract-authoring/the-data-contract): |
| 68 | + |
| 69 | +```prisma |
| 70 | +// use prisma-next |
| 71 | +
|
| 72 | +model User { |
| 73 | + id Int @id @default(autoincrement()) |
| 74 | + email String @unique |
| 75 | + username String? |
| 76 | + name String? |
| 77 | + posts Post[] |
| 78 | + createdAt DateTime @default(now()) |
| 79 | + updatedAt temporal.updatedAt() |
| 80 | +} |
| 81 | +
|
| 82 | +model Post { |
| 83 | + id Int @id @default(autoincrement()) |
| 84 | + title String |
| 85 | + content String? |
| 86 | + author User @relation(fields: [authorId], references: [id]) |
| 87 | + authorId Int |
| 88 | + createdAt DateTime @default(now()) |
| 89 | + updatedAt temporal.updatedAt() |
| 90 | +} |
| 91 | +``` |
| 92 | + |
| 93 | +Compile it, [plan a migration](https://www.prisma.io/docs/orm/next/migrations/generating-a-migration), [apply it](https://www.prisma.io/docs/orm/next/migrations/applying-a-migration): |
| 94 | + |
| 95 | +```bash |
| 96 | +npx prisma-next contract emit |
| 97 | +npx prisma-next migration plan --name init_users_posts |
| 98 | +npx prisma-next migrate --advance-ref db |
| 99 | +``` |
| 100 | + |
| 101 | +`--advance-ref db` moves a [ref](https://www.prisma.io/docs/orm/next/migrations/the-migration-graph#name-important-states-with-refs), a name pinned to a point in your migration history, onto what you just applied. Later plans start from there and produce a delta instead of recreating everything. |
| 102 | + |
| 103 | +### Step 3: Change the model |
| 104 | + |
| 105 | +Add an enum, two fields, and a boolean: |
| 106 | + |
| 107 | +```prisma |
| 108 | +enum Role { |
| 109 | + USER |
| 110 | + EDITOR |
| 111 | + ADMIN |
| 112 | +} |
| 113 | +
|
| 114 | +model User { |
| 115 | + id Int @id @default(autoincrement()) |
| 116 | + email String @unique |
| 117 | + username String? |
| 118 | + name String? |
| 119 | + bio String? |
| 120 | + role Role @default(USER) |
| 121 | + posts Post[] |
| 122 | + createdAt DateTime @default(now()) |
| 123 | + updatedAt temporal.updatedAt() |
| 124 | +} |
| 125 | +
|
| 126 | +model Post { |
| 127 | + id Int @id @default(autoincrement()) |
| 128 | + title String |
| 129 | + content String? |
| 130 | + published Boolean @default(false) |
| 131 | + author User @relation(fields: [authorId], references: [id]) |
| 132 | + authorId Int |
| 133 | + createdAt DateTime @default(now()) |
| 134 | + updatedAt temporal.updatedAt() |
| 135 | +} |
| 136 | +``` |
| 137 | + |
| 138 | +```bash |
| 139 | +npx prisma-next contract emit |
| 140 | +npx prisma-next migration plan --name add_roles_and_publishing |
| 141 | +npx prisma-next migrate --advance-ref db |
| 142 | +``` |
| 143 | + |
| 144 | +Repeat for whatever your app needs; when a change needs a backfill, [Data Migrations in Prisma Next](/data-migrations-in-prisma-next) covers that. The history behind the screenshots here has six migrations: an initial pair of models, this enum-and-fields change, a `Category` model with a relation and two unique constraints, a destructive column drop, and two more field additions. |
| 145 | + |
| 146 | +### Step 4: Add some data |
| 147 | + |
| 148 | +A history reads better next to real rows: |
| 149 | + |
| 150 | +```bash |
| 151 | +npm run db:seed |
| 152 | +``` |
| 153 | + |
| 154 | +### Step 5: Open Studio |
| 155 | + |
| 156 | +A Prisma Next project has no `schema.prisma`, so Studio takes the connection string with `--url`. It lives in `.env` rather than your shell, so load it first: |
| 157 | + |
| 158 | +```bash |
| 159 | +set -a && . ./.env && set +a |
| 160 | +npx prisma@dev studio --url "$DATABASE_URL" |
| 161 | +``` |
| 162 | + |
| 163 | +Studio opens on `http://localhost:5555`, and **Migrations** is in the left navigation. |
| 164 | + |
| 165 | +## Reading a migration |
| 166 | + |
| 167 | +Select `add_roles_and_publishing`. The canvas shows the `Role` enum as a new card, `User` amber with `bio` and `role` marked `+`, and `Post` amber with `published`. |
| 168 | + |
| 169 | +Open the **SQL** panel and you get exactly what ran, labelled with its operation class: |
| 170 | + |
| 171 | + |
| 172 | + |
| 173 | +Note the last statement. Prisma Next implements `Role` as a `text` column plus a `CHECK` constraint rather than a native Postgres enum type. The canvas shows you the modelling intent; the SQL panel shows you the implementation. |
| 174 | + |
| 175 | +The **Schema** panel renders the same change as a Prisma-schema diff, with long unchanged runs collapsed into folds: |
| 176 | + |
| 177 | + |
| 178 | + |
| 179 | +By default the canvas draws only the models a migration touched plus their direct neighbors. Toggle **All models** to see the whole schema as it stood at that point in history: |
| 180 | + |
| 181 | + |
| 182 | + |
| 183 | +The selected migration is part of the URL. In Console that means a link drops a reviewer straight onto the change you're asking about. Locally it's a bookmark for yourself. |
| 184 | + |
| 185 | +Your tables are in the same session under **Tables**, so you can go from "what changed" to "what's in there" without leaving the app. [Getting Started with Studio](https://www.prisma.io/docs/studio/getting-started) covers editing, filtering, and exporting: |
| 186 | + |
| 187 | + |
| 188 | + |
| 189 | +## Where the history comes from |
| 190 | + |
| 191 | +Studio never opens your `migrations/` directory and never calls the Prisma Next CLI. It reads two tables that Prisma Next maintains in your database: |
| 192 | + |
| 193 | +- **`prisma_contract.ledger`** holds one row per applied migration: the name, the apply time, the executed operations with their SQL, and the two contract hashes the migration moved between. |
| 194 | +- **`prisma_contract.contract`** stores each distinct contract once, keyed by its hash. |
| 195 | + |
| 196 | +Every ledger row names the contract it started from and the contract it produced. Studio looks both up by hash. There is nothing to reconstruct and nothing to guess. |
| 197 | + |
| 198 | +Writing only the destination contract on each apply is enough to cover both ends of every row. The first migration starts from the empty contract. Every origin after that was some earlier apply's destination, so it is already stored. |
| 199 | + |
| 200 | +The practical consequence: a migration applied from CI, from a teammate's laptop, or from a branch you never checked out shows up in your Studio with a full diff. The history belongs to the database. The hashes are the same ones that make Prisma Next migrations [a graph rather than a numbered list](https://www.prisma.io/docs/orm/next/migrations/the-migration-graph). |
| 201 | + |
| 202 | +## Where you can use it |
| 203 | + |
| 204 | +The Migrations view shipped in `@prisma/studio-core` 0.32.0. The Prisma CLI bundles Studio, and a new enough version is currently only in the CLI's `dev` release, so use `npx prisma@dev studio` to try it locally. |
| 205 | + |
| 206 | +It is also in the embedded Studio in [Prisma Console](https://console.prisma.io), for any database with an applied Prisma Next migration history. Open your database's Studio tab and select **Migrations**. No local setup, and the selected migration is part of the Console URL too. |
| 207 | + |
| 208 | +A few limits worth stating plainly: |
| 209 | + |
| 210 | +- **Prisma Next on PostgreSQL.** The view needs the `prisma_contract.ledger` table. Prisma ORM projects using `prisma migrate` record their history differently and won't show it. |
| 211 | +- **Applied migrations only.** A migration you've planned but not applied isn't in the database, so it isn't in the view. |
| 212 | +- **An empty history hides the view.** No applied migrations, no **Migrations** item. |
| 213 | +- **Older databases lose the diffs.** If your database was migrated by a Prisma Next that predates the contract store, you keep the list and the SQL panel, and the canvas asks you to update. |
| 214 | + |
| 215 | +## Where this fits |
| 216 | + |
| 217 | +You already model data as a contract and apply migrations to [Prisma Postgres](https://www.prisma.io/docs/postgres). The missing piece was reading back what those migrations did to a specific database. That record used to live only in files, describing intent. Now Studio shows what ran. |
| 218 | + |
| 219 | +This matters most where the repo can't help you. The database your app talks to in production was migrated by CI, not by you. Its history is in the ledger, and Studio reads the ledger. The same timeline is there whether you deploy on [Prisma Compute](https://www.prisma.io/docs/compute) or anywhere else, and the embedded Studio in Console shows it to everyone on your team without a local checkout. |
| 220 | + |
| 221 | +## Frequently asked questions |
| 222 | + |
| 223 | +<Accordions type="single"> |
| 224 | + <Accordion title="What is the Migrations view in Prisma Studio?"> |
| 225 | +The Migrations view is a screen in Prisma Studio that lists every applied migration of a Prisma Next database, newest first, with a visual diff of the models it changed, the SQL it executed, and a Prisma-schema diff. It shipped in `@prisma/studio-core` 0.32.0 and reads the history from the database itself. |
| 226 | + </Accordion> |
| 227 | + <Accordion title="Why doesn't the Migrations item appear in my Prisma Studio?"> |
| 228 | +The Migrations item appears only when the connected database has at least one applied Prisma Next migration, recorded in the `prisma_contract.ledger` table. It stays hidden for databases with no applied migrations, for Prisma ORM projects using `prisma migrate`, and for Studio versions older than `@prisma/studio-core` 0.32.0. The stable Prisma CLI still bundles an older Studio, so run `npx prisma@dev studio`. |
| 229 | + </Accordion> |
| 230 | + <Accordion title="Does the Migrations view work with Prisma ORM and prisma migrate?"> |
| 231 | +No. Projects managed with `prisma migrate` record their history in the `_prisma_migrations` table, which the view does not read. The Migrations view requires a Prisma Next project on PostgreSQL, which records each apply in `prisma_contract.ledger`. |
| 232 | + </Accordion> |
| 233 | + <Accordion title="Where does Prisma Studio read the migration history from?"> |
| 234 | +From the database, not from your repo. Prisma Next writes one row per applied migration to `prisma_contract.ledger` and stores each schema snapshot in `prisma_contract.contract`, keyed by hash. Studio joins the two, so migrations applied from CI or another machine appear with a full diff. |
| 235 | + </Accordion> |
| 236 | +</Accordions> |
| 237 | + |
| 238 | +## Try it |
| 239 | + |
| 240 | +```bash |
| 241 | +npm create prisma@next |
| 242 | +``` |
| 243 | + |
| 244 | +Model something, apply two migrations, and open **Migrations**. Tell us what you'd want in the timeline next on [Discord](https://pris.ly/discord). |
| 245 | + |
| 246 | +**Star and watch [prisma/prisma-next](https://pris.ly/pn-gh) on GitHub** to follow development. |
| 247 | + |
| 248 | +--- |
| 249 | + |
| 250 | +The Migrations view shipped in `@prisma/studio-core` 0.32.0. The Prisma CLI bundles Studio, and a new enough version is currently only in the CLI's `dev` release, hence `npx prisma@dev studio`. [Prisma Next is in Early Access](https://www.prisma.io/blog/prisma-next-early-access-write-your-contract-prompt-your-agent-ship-your-app) and not production-ready yet. Prisma 7 is still the right choice for production today. When Prisma Next is ready for general use, it becomes Prisma 8. |
0 commit comments