Skip to content

Prisma and Drizzle migrations in production

Run prisma migrate deploy or drizzle-kit migrate on the server with DATABASE_URL from a Read-only Production context. No DATABASE_URL in a file.

Oct 10, 2026 · 4 min read

A server token opens the Read-only Production context, getmyenv run starts the migration, and the database gets the new schema.
A server token reads Production. getmyenv run gives the migration DATABASE_URL, with no file on disk.

Where DATABASE_URL comes from

Prisma reads the URL with env("DATABASE_URL"). The drizzle-kit config in Drizzle's getting started guide reads process.env.DATABASE_URL:

ts
import "dotenv/config"; import { defineConfig } from "drizzle-kit"; export default defineConfig({ dialect: "postgresql", schema: "./src/db/schema.ts", out: "./drizzle", dbCredentials: { url: process.env.DATABASE_URL! }, });

Both read the environment. A variable already set wins over a .env file, because dotenv does not replace values that are set. So run can supply DATABASE_URL, and the config stays as it is.

1. Set DATABASE_URL in Production

Only the owner sets Read-only values, in the dashboard. Open the project, pick Production, then Add variable. Values are encrypted in the browser.

For Development, set it from the CLI. It asks for the value:

bash
npx getmyenv set DATABASE_URL

2. Migrate on the server

Create a server token for Production in Project settings, Tokens. On the server:

bash
export GETMYENV_TOKEN=... # server token for Production # Prisma npx getmyenv run production -- npx prisma migrate deploy # Drizzle npx getmyenv run production -- npx drizzle-kit migrate

The token holds the Production key, so there is no Vault password on the server. The first run from a new machine waits for your approval on Requests, unless the token trusts machines from its allowed IPs. A machine's request waits up to 5 minutes for approval.

run checks that every variable has a value before it starts. Then start the app the same way: npx getmyenv run production -- node server.js.

Prisma and drizzle-kit read DATABASE_URL themselves. Do not write $DATABASE_URL on the command line. Your shell would expand it before run starts. The $VAR gotcha.

3. In development

bash
npx getmyenv run -- npx prisma migrate dev npx getmyenv run -- npx drizzle-kit migrate

Without a context, run uses the folder's context, Development by default. Only a server token reads a Read-only context, so the Production URL stays off your laptop.

Keep DATABASE_URL out of committed files

bash
git log --oneline --all -- .env # was it ever committed? git rm --cached .env
  • git rm --cached stops tracking the file. It stays in your history. If the URL was ever committed, change the database password.
  • run does not read .env files. Delete them when you are ready.
  • If a tool must read a file, npx getmyenv export writes one. That file is plaintext.

Related docs: Machine access, Contexts, How run works, Vercel and Netlify