Setting Up Prisma for Normal and Edge Environments
When building modern web applications, you'll often need to deploy to different runtime environments. Traditional Node.js environments and edge runtimes like Vercel Edge Functions or Cloudflare Workers have different capabilities and limitations. This guide walks you through setting up Prisma for both scenarios with clear explanations and practical examples.
Understanding the Difference
Normal environments run on traditional Node.js servers with full access to the Node.js API, TCP connections, filesystem operations, and server-side rendering capabilities. These environments provide the most comprehensive feature set but are typically bound to specific geographic locations.
Edge environments operate with a limited runtime that only supports Web APIs. They cannot establish TCP connections and must rely on HTTP or WebSocket protocols instead. While they lack filesystem access, edge runtimes compensate by running closer to users globally, resulting in significantly reduced latency for end users.
Prerequisites and Installation
Before setting up Prisma, you'll need to install the core packages. Start with the basic Prisma installation using npm install prisma @prisma/client
. This provides the foundation for both environment types.
For edge environments, you'll additionally need the Prisma Accelerate extension, which you can install with npm install @prisma/extension-accelerate
. This extension is crucial for edge compatibility as it handles connection pooling and caching through Prisma's hosted service.
If you're working with specialized database adapters, you have additional options. For Neon PostgreSQL, install @neondatabase/serverless @prisma/adapter-neon ws
. For standard PostgreSQL with the pg adapter, use npm install pg @prisma/adapter-pg
along with the development dependency npm install -D @types/pg
.
Environment Configuration
Your database connection configuration differs between normal and edge environments. For normal environments, set your standard PostgreSQL connection string in your .env
file as DATABASE_URL="postgresql://username:password@localhost:5432/mydb"
.
Edge environments require Prisma Accelerate, so you'll need to configure PRISMA_ACCELERATE_URL="prisma://accelerate.prisma-data.net/?api_key=your_api_key"
instead. This URL connects to Prisma's hosted connection pooling service, which translates your database operations into edge-compatible requests.
Normal Environment Setup
For traditional Node.js environments, create a lib/prisma.ts
file with a straightforward configuration. The setup focuses on creating a single Prisma instance that's cached globally during development to prevent multiple connections.
1import { PrismaClient } from '@prisma/client'; 2 3const globalForPrisma = globalThis as unknown as { 4 prisma: PrismaClient | undefined 5}; 6 7export const prisma = globalForPrisma.prisma ?? new PrismaClient({ 8 log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'], 9}); 10 11if (process.env.NODE_ENV !== 'production') { 12 globalForPrisma.prisma = prisma; 13} 14 15// Optional: Test connection on startup 16prisma.$connect() 17 .then(() => { 18 console.log('â Successfully connected to database'); 19 }) 20 .catch((error) => { 21 console.error('â Database connection failed:', error); 22 process.exit(1); 23 });
This configuration includes global instance caching to prevent multiple Prisma instances in development, which can lead to connection pool exhaustion. The logging configuration provides detailed query logs during development while keeping only error logs in production. The optional connection testing validates database connectivity when your application starts, helping catch configuration issues early.
Edge Environment Setup
Edge runtimes require a different approach due to their limitations. Create a separate lib/prisma-edge.ts
file that uses the edge-compatible Prisma client with the Accelerate extension.
1import { PrismaClient } from '@prisma/client/edge'; 2import { withAccelerate } from '@prisma/extension-accelerate'; 3 4const globalForPrisma = globalThis as unknown as { 5 prisma: PrismaClient | undefined 6}; 7 8export const prisma = globalForPrisma.prisma ?? 9 new PrismaClient().$extends(withAccelerate()); 10 11if (process.env.NODE_ENV !== 'production') { 12 globalForPrisma.prisma = prisma; 13}
The key difference here is the import from @prisma/client/edge
and the mandatory use of the withAccelerate()
extension. Edge environments cannot test connections on startup like normal environments, so the connection testing code is omitted. The Accelerate extension handles connection pooling and provides caching capabilities that are essential for edge performance.
Advanced Database Adapter Configurations
When working with specific database providers, you might want to use specialized adapters for better performance. The Neon PostgreSQL adapter configuration requires additional setup for WebSocket connections.
1import { Pool, neonConfig } from '@neondatabase/serverless'; 2import { PrismaNeon } from '@prisma/adapter-neon'; 3import { PrismaClient } from '@prisma/client'; 4import ws from 'ws'; 5 6// Configure Neon for WebSocket connections 7neonConfig.webSocketConstructor = ws; 8neonConfig.useSecureWebSocket = true; 9neonConfig.pipelineConnect = false; 10 11const connectionString = process.env.DATABASE_URL!; 12 13const pool = new Pool({ 14 connectionString, 15 ssl: { rejectUnauthorized: true }, 16 max: 5, // Optimal for serverless 17}); 18 19const adapter = new PrismaNeon(pool); 20const prismaClient = new PrismaClient({ adapter }); 21 22const globalForPrisma = globalThis as unknown as { 23 prisma: PrismaClient | undefined 24}; 25 26export const prisma = globalForPrisma.prisma ?? prismaClient; 27 28if (process.env.NODE_ENV !== 'production') { 29 globalForPrisma.prisma = prisma; 30}
This configuration specifically optimizes for Neon's infrastructure by configuring WebSocket settings and SSL requirements. The connection pool is limited to 5 connections, which is optimal for serverless environments where you want to avoid overwhelming your database with too many concurrent connections.
For traditional PostgreSQL deployments, the pg adapter provides excellent performance with standard TCP connections.
1import { Pool } from 'pg'; 2import { PrismaPg } from '@prisma/adapter-pg'; 3import { PrismaClient } from '@prisma/client'; 4 5const connectionString = process.env.DATABASE_URL!; 6const pool = new Pool({ connectionString }); 7const adapter = new PrismaPg(pool); 8 9const prismaClient = new PrismaClient({ adapter }); 10 11const globalForPrisma = globalThis as unknown as { 12 prisma: PrismaClient | undefined 13}; 14 15export const prisma = globalForPrisma.prisma ?? prismaClient; 16 17if (process.env.NODE_ENV !== 'production') { 18 globalForPrisma.prisma = prisma; 19}
Usage Patterns
When implementing API routes in normal environments, you can directly import your Prisma instance and use it with full feature support. Error handling should always be implemented to gracefully handle database connection issues or query failures.
1// pages/api/users.ts or app/api/users/route.ts 2import { prisma } from '@/lib/prisma'; 3 4export async function GET() { 5 try { 6 const users = await prisma.user.findMany(); 7 return Response.json(users); 8 } catch (error) { 9 return Response.json({ error: 'Failed to fetch users' }, { status: 500 }); 10 } 11}
Edge functions require the edge-compatible Prisma client and benefit from caching strategies provided by Prisma Accelerate. The runtime declaration ensures your function deploys to the edge environment.
1// app/api/users/route.ts (Edge Runtime) 2import { prisma } from '@/lib/prisma-edge'; 3 4export const runtime = 'edge'; 5 6export async function GET() { 7 try { 8 const users = await prisma.user.findMany({ 9 cacheStrategy: { ttl: 60 }, // Accelerate caching 10 }); 11 return Response.json(users); 12 } catch (error) { 13 return Response.json({ error: 'Failed to fetch users' }, { status: 500 }); 14 } 15}
Performance Considerations
Normal environments provide the fastest database access through direct TCP connections and benefit from full connection pooling managed by your database adapter. All Prisma features are available, including advanced query capabilities and real-time subscriptions.
Edge environments introduce HTTP and WebSocket overhead, typically resulting in 10-15% slower database operations compared to TCP connections. However, this performance penalty is often offset by the global distribution advantage, where edge functions run much closer to your users. The intelligent caching provided by Prisma Accelerate can significantly improve response times for repeated queries, and edge functions generally have faster cold start times than traditional serverless functions.
Deployment Strategy
When deploying to normal environments, ensure your DATABASE_URL
environment variable is properly configured and that your build process includes prisma generate
. Run database migrations using prisma db push
for development or prisma migrate deploy
for production deployments. Verify that your database accepts connections from your server's IP addresses or security groups.
Edge environment deployment requires setting up Prisma Accelerate first, then configuring the PRISMA_ACCELERATE_URL
in your deployment environment. Always use the @prisma/client/edge
import in your edge functions and test your deployment thoroughly to ensure caching behavior works as expected. Monitor your Accelerate usage to understand query patterns and optimize accordingly.
Troubleshooting Common Issues
Module resolution errors in edge environments typically indicate incorrect import paths. Ensure you're importing from @prisma/client/edge
rather than the standard client, and verify that Prisma Accelerate is properly configured with the correct URL and API key.
Connection timeout issues often stem from incorrect connection strings, firewall restrictions, or network security group configurations. For edge environments, verify that your Accelerate URL is correct and that your API key has the necessary permissions.
Global instance conflicts can cause unexpected behavior during development. Clear your Next.js cache by removing the .next
directory and restarting your development server. This resolves most caching-related issues that occur when switching between different Prisma configurations.