Overview
Prisma ORM works seamlessly in production environments across various platforms. This guide covers deployment strategies, configuration management, and platform-specific considerations.
Configuration Management
Using prisma.config.ts
Prisma 7 introduces prisma.config.ts for managing database connections and configuration:
import { defineConfig, env } from '@prisma/config'
export default defineConfig({
datasource: {
url: env('DATABASE_URL'),
},
})
The env() helper safely loads environment variables at runtime, eliminating the need for .env files in production.
Environment Variables
Store sensitive credentials in environment variables:
DATABASE_URL="postgresql://user:password@host:5432/dbname"
Never commit credentials to version control. Use platform-specific secret management services.
Vercel
Prisma works out-of-the-box on Vercel:
import { PrismaClient } from '@prisma/client'
// Singleton pattern for serverless
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined
}
export const prisma = globalForPrisma.prisma ?? new PrismaClient()
if (process.env.NODE_ENV !== 'production') {
globalForPrisma.prisma = prisma
}
AWS Lambda
For Lambda, use driver adapters with connection pooling:
import { PrismaPg } from '@prisma/adapter-pg'
import { PrismaClient } from '@prisma/client'
import { Pool } from 'pg'
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 10,
})
const adapter = new PrismaPg({ pool })
const prisma = new PrismaClient({ adapter })
Edge Runtime
Cloudflare Workers
Use the D1 adapter for Cloudflare D1 databases:
import { PrismaD1 } from '@prisma/adapter-d1'
import { PrismaClient } from '@prisma/client'
export default {
async fetch(request: Request, env: Env) {
const adapter = new PrismaD1(env.DB)
const prisma = new PrismaClient({ adapter })
const users = await prisma.user.findMany()
return Response.json(users)
},
}
Container Deployment
Docker
Multi-stage Dockerfile for optimized builds:
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
COPY prisma ./prisma/
RUN npm ci
RUN npx prisma generate
COPY . .
RUN npm run build
# Production image
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/prisma ./prisma
EXPOSE 3000
CMD ["node", "dist/index.js"]
Prisma Client is generated during the build step and doesn’t require the Prisma CLI at runtime.
Database Connection Management
Connection Limits
Be mindful of database connection limits:
const prisma = new PrismaClient({
// PostgreSQL default max_connections is 100
// Leave headroom for other services
})
Exceeding connection limits will cause errors:Error querying the database: FATAL: sorry, too many clients already
Graceful Shutdown
Always disconnect on application shutdown:
process.on('SIGINT', async () => {
await prisma.$disconnect()
process.exit(0)
})
process.on('SIGTERM', async () => {
await prisma.$disconnect()
process.exit(0)
})
Driver Adapters
Prisma 7 uses JavaScript driver adapters for database connectivity:
PostgreSQL
node-postgres (pg)
import { PrismaPg } from '@prisma/adapter-pg'
import { Pool } from 'pg'
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
})
const adapter = new PrismaPg({ pool })
const prisma = new PrismaClient({ adapter })
Neon Serverless
import { PrismaNeon } from '@prisma/adapter-neon'
import { Pool } from '@neondatabase/serverless'
const pool = new Pool({ connectionString: process.env.DATABASE_URL })
const adapter = new PrismaNeon({ pool })
const prisma = new PrismaClient({ adapter })
SQLite
better-sqlite3
import { PrismaBetterSqlite3 } from '@prisma/adapter-better-sqlite3'
import Database from 'better-sqlite3'
const db = new Database('prisma/dev.db')
const adapter = new PrismaBetterSqlite3(db)
const prisma = new PrismaClient({ adapter })
Turso/LibSQL
import { PrismaLibSQL } from '@prisma/adapter-libsql'
import { createClient } from '@libsql/client'
const client = createClient({
url: process.env.TURSO_DATABASE_URL,
authToken: process.env.TURSO_AUTH_TOKEN,
})
const adapter = new PrismaLibSQL(client)
const prisma = new PrismaClient({ adapter })
Migration Strategy
Production Migrations
Run migrations as part of your deployment pipeline:
# In your CI/CD pipeline
npx prisma migrate deploy
Never use prisma migrate dev in production. Use prisma migrate deploy instead.
Zero-Downtime Deployments
For zero-downtime deployments:
- Expand phase: Add new columns/tables (backward compatible)
- Deploy application: Code uses both old and new schema
- Migrate data: Populate new columns from old data
- Contract phase: Remove old columns/tables
Monitoring and Logging
Enable query logging for debugging:
const prisma = new PrismaClient({
log: [
{ emit: 'event', level: 'query' },
{ emit: 'event', level: 'error' },
{ emit: 'event', level: 'warn' },
],
})
prisma.$on('query', (e) => {
console.log('Query: ' + e.query)
console.log('Duration: ' + e.duration + 'ms')
})
Disable query logging in production for better performance. Enable only for debugging specific issues.
Best Practices
- Use connection pooling for serverless environments
- Implement singleton pattern to reuse PrismaClient instances
- Set appropriate timeouts for your workload
- Monitor query performance with logging
- Use environment-specific configurations via
prisma.config.ts
- Handle disconnections gracefully on shutdown
- Keep migrations in version control and deploy them systematically
Security Checklist