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

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:
tsimport "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:
bashnpx getmyenv set DATABASE_URL
2. Migrate on the server
Create a server token for Production in Project settings, Tokens. On the server:
bashexport 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
bashnpx 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
bashgit log --oneline --all -- .env # was it ever committed? git rm --cached .env
git rm --cachedstops 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 exportwrites one. That file is plaintext.
Related docs: Machine access, Contexts, How run works, Vercel and Netlify