To secure a Cursor + Prisma + Vercel stack, you need to: (1) store your DATABASE_URL in Vercel environment variables (never in code), (2) use Prisma's standard query methods which automatically prevent SQL injection, (3) avoid string interpolation in $queryRaw calls or use proper parameterization, (4) implement authorization checks in all API routes since Prisma lacks built-in RLS, and (5) create a .cursorignore file to prevent AI from accessing your .env files. This blueprint covers Prisma's security benefits, raw query dangers, and authorization patterns.
TL;DR
Prisma provides type-safe database access and prevents most SQL injection attacks by default. Key security tasks: store DATABASE_URL in Vercel environment variables, use Prisma's query methods (not raw SQL when possible), implement authorization checks in your API routes, and be careful with $queryRaw which bypasses Prisma's protections.
Platform Guides & Checklists
Cursor Security Guide
Prisma Security Guide
Vercel Security Guide
Pre-Launch Checklist
Stack Overview
Prisma is a type-safe ORM that generates a database client from your schema. This stack is excellent for type safety and developer experience:
| Component | Role | Security Benefit |
|---|---|---|
| Cursor | AI code editor | Type hints help catch errors |
| Prisma | Database ORM | Type-safe queries prevent injection |
| Vercel | Hosting | Secure env vars, serverless functions |
Part 1: Prisma Security Benefits Prisma
Built-in SQL Injection Protection Prisma
Prisma's query methods automatically parameterize inputs:
// This is safe - Prisma parameterizes the input
const user = await prisma.user.findUnique({
where: { email: userInput } // Safe even if userInput is malicious
});
// Also safe
const posts = await prisma.post.findMany({
where: {
title: { contains: searchQuery }, // Parameterized
authorId: userId // Parameterized
}
});
Danger: Raw Queries Prisma Cursor
The main injection risk in Prisma is using $queryRaw incorrectly:
// NEVER do this - SQL injection vulnerability
const users = await prisma.$queryRaw`
SELECT * FROM users WHERE name = '${userInput}'
`;
// This bypasses Prisma's protection!
// Safe: Use template literal without quotes
const users = await prisma.$queryRaw`
SELECT * FROM users WHERE name = ${userInput}
`;
// Note: Template literal without quotes around ${userInput}
AI code risk: Cursor might generate raw SQL queries for complex operations. Always review any $queryRaw or $executeRaw usage for proper parameterization.
Part 2: Database Connection Security Prisma Vercel
# Never commit this file
DATABASE_URL="postgresql://user:password@host:5432/database?sslmode=require"
# For connection pooling with Prisma (recommended for serverless)
DATABASE_URL="postgresql://user:password@host:5432/database?pgbouncer=true"
DIRECT_URL="postgresql://user:password@host:5432/database"
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL") // For migrations
}
Part 3: Authorization Patterns Vercel
Prisma doesn't have built-in row-level security. Implement authorization in your application:
// lib/auth.ts
export async function getAuthorizedPost(postId: string, userId: string) {
const post = await prisma.post.findUnique({
where: { id: postId }
});
if (!post) {
throw new Error('Post not found');
}
if (post.authorId !== userId) {
throw new Error('Not authorized');
}
return post;
}
// In API route
export async function PUT(request: Request) {
const session = await getSession();
if (!session) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
const { id, title, content } = await request.json();
await getAuthorizedPost(id, session.user.id);
const updated = await prisma.post.update({
where: { id },
data: { title, content }
});
return Response.json(updated);
}
Security Checklist
Pre-Launch Checklist for Cursor + Prisma + Vercel
DATABASE_URL in Vercel env vars (not in code)
.env files in .gitignore
No string interpolation in $queryRaw
Authorization checks on all protected routes
Sensitive fields excluded from responses
Input validation with Zod or similar
Connection pooling configured for serverless
SSL required for database connection
.cursorignore excludes .env files
Alternative Stack Configurations
Cursor + Supabase + Vercel Swap Prisma for Supabase client with built-in RLS. Different ORM approach with PostgreSQL security.
Cursor + PlanetScale + Vercel
Prisma with PlanetScale MySQL. Same ORM security, different database backend.
T3 Stack Security
Full T3 stack with Prisma, tRPC, and Next.js. Type-safe end-to-end security.
Is Prisma safe from SQL injection?
Yes, when using Prisma's standard query methods. All inputs are automatically parameterized. The only risk is using $queryRaw with string interpolation, which bypasses Prisma's protections.
Do I need connection pooling on Vercel?
Yes, strongly recommended. Serverless functions can create many database connections. Use Prisma's built-in connection pooling or services like PgBouncer to prevent connection exhaustion.