This error occurs when Prisma tries to create foreign key constraints in your schema but the database doesn't support them (like PlanetScale). Resolve it by switching to emulated relations mode or enabling foreign key support in your database.
The "P3021: Foreign keys cannot be created on this database" error appears when Prisma attempts to create foreign key constraints during migration, but your database provider doesn't support them natively. This is most common with PlanetScale, a MySQL-compatible serverless database that originally didn't allow traditional foreign key constraints at the database level. Prisma ORM offers two ways to handle relations: the default "foreignKeys" mode that uses database-level constraints, and the "prisma" mode that emulates relations at the application level. When you use a database that doesn't support foreign keys, Prisma cannot apply the default mode and throws the P3021 error during migration. Since February 2024, PlanetScale added support for foreign key constraints, so this error is now more commonly encountered with other serverless or restricted database environments.
First, verify what database you're using and whether it supports foreign keys:
# Check your DATABASE_URL in .env.local or .env
cat .env.local | grep DATABASE_URLCommon databases that need special handling:
- PlanetScale (MySQL-compatible, serverless)
- Turso (SQLite-compatible, serverless)
- Neon (PostgreSQL, but with connection limits)
- CockroachDB (distributed SQL)
- SQLite (limited foreign key support)
For PlanetScale: Since February 2024, foreign key support is available. Check your database settings to enable it.
If you're using PlanetScale and it's a recent database, enable foreign key constraints:
1. Go to your PlanetScale dashboard
2. Navigate to your database settings
3. Look for "Foreign Key Constraints" setting
4. Toggle it to Enable
5. Save changes
Once enabled, you can use the default Prisma configuration. If enabling foreign keys isn't an option (older PlanetScale branches), proceed to the next step.
If your database doesn't support foreign keys, configure Prisma to emulate relations at the application level instead:
In your prisma/schema.prisma, update the datasource block:
datasource db {
provider = "mysql" // or "sqlite", "postgresql", etc.
url = env("DATABASE_URL")
relationMode = "prisma" // Add this line
}This tells Prisma to:
- Skip creating database-level foreign key constraints
- Handle referential actions (CASCADE, SET NULL, etc.) at the Prisma Client level
- Allow migrations to succeed on databases without foreign key support
After adding relationMode = "prisma", your database operations will work as before, but constraints are enforced by Prisma instead of the database.
When using relationMode = "prisma", Prisma doesn't automatically create indexes on foreign key fields. You must add them manually for good query performance:
For example, if you have a Blog with Posts and Comments:
model Post {
id Int @id @default(autoincrement())
title String
content String
blogId Int
blog Blog @relation(fields: [blogId], references: [id], onDelete: Cascade)
comments Comment[]
@@index([blogId]) // Add this index!
}
model Comment {
id Int @id @default(autoincrement())
text String
postId Int
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
@@index([postId]) // Add this index!
}
model Blog {
id Int @id @default(autoincrement())
name String
posts Post[]
}The @@index([fieldName]) directive creates a database index on the foreign key field. This prevents full table scans and keeps query performance fast. Without indexes, lookups can become slow and expensive (especially on providers that bill per accessed row).
Once you've updated your schema with relationMode = "prisma" and added indexes, apply the changes:
# Option 1: Using db push (recommended for development)
npx prisma db push
# Option 2: Create and run a migration
npx prisma migrate dev --name add_indexesYou should see output like:
The following migration(s) have been created and applied:
./prisma/migrations/[timestamp]_init/migration.sql
All migrations have been successfully applied to your database.If you still get P3021 errors after updating relationMode, ensure:
1. Your .env.local has the correct DATABASE_URL
2. You've saved the schema.prisma file
3. Your Prisma Client is regenerated (npx prisma generate)
After migration, test your relations to ensure they work correctly:
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
// Create a blog
const blog = await prisma.blog.create({
data: { name: 'My Blog' }
});
// Create a post (this will enforce the relation via Prisma)
const post = await prisma.post.create({
data: {
title: 'First Post',
content: 'Hello World',
blogId: blog.id
}
});
// Create a comment
const comment = await prisma.comment.create({
data: {
text: 'Nice post!',
postId: post.id
}
});
console.log('Relations work correctly!');If queries fail with referential action errors, check that your @@index directives are correctly placed and migrated.
Ensure your setup is fully compatible:
# Check Prisma version
npm list @prisma/client
# Recommended: Upgrade to latest Prisma if you're below v3.0
npm install @prisma/client@latest @prisma/cli@latest
# Regenerate Prisma Client
npx prisma generateCompatibility matrix:
| Database | Provider | relationMode | Foreign Keys |
|----------|----------|--------------|--------------|
| PlanetScale (2024+) | mysql | foreignKeys | Supported |
| PlanetScale (pre-2024) | mysql | prisma | Not supported |
| Turso | sqlite | prisma | Limited support |
| Neon | postgresql | foreignKeys | Supported |
| CockroachDB | postgresql | foreignKeys | Supported |
| AWS Aurora | mysql/postgresql | foreignKeys | Supported |
Choose relationMode = "prisma" only if your database doesn't support foreign keys.
Referential Actions with relationMode = "prisma": When using Prisma mode, referential actions (CASCADE, SET NULL, RESTRICT, etc.) are handled by Prisma during update/delete operations, not by the database. This means:
- Creating records doesn't enforce foreign key constraints (you can create orphaned records)
- Updating/deleting parent records WILL cascade or set to null based on your @relation definition
- Performance is slightly slower than database-enforced constraints (no atomic operations)
Combining relationMode with TypeScript: Always define your types properly:
// Safe: Prisma infers types
const post = await prisma.post.create({
data: { title, content, blogId }
});
// Prisma will throw if blogId doesn't exist when using cascadeMigrating FROM foreignKeys TO prisma: If you're switching relation modes:
1. Add relationMode = "prisma" to datasource
2. Add @@index to all relation scalar fields
3. Run npx prisma migrate dev to create migration
4. Existing data is preserved - only the schema changes
Performance implications:
- With relationMode = "prisma", always index relation fields (blogId, postId, etc.)
- Without indexes, every relation operation requires a full table scan
- Use @@index on composite foreign keys too: @@index([authorId, createdAt])
Testing in development: Temporarily remove foreign key constraints from Prisma schema to test P3021 scenarios:
// Temporarily remove to test migration
// @relation(fields: [...], references: [...])This helps diagnose whether the issue is with relation definitions or database support.
P1013: The provided database string is invalid
The provided database string is invalid
P1000: Authentication failed against database server
Authentication failed against database server
P1010: User was denied access on the database
How to fix "P1010: User was denied access on the database" in Prisma
P5008: Usage exceeded, upgrade your plan (Accelerate)
How to fix "Usage exceeded, upgrade your plan" in Prisma Accelerate
Value out of range for the type
How to fix 'P2020: Value out of range for the type' in Prisma