How to Extend Prisma Schema Using Antigravity
Learn how to extend your Prisma schema with Antigravity's MCP integration. Add models, relations, migrations, and complex patterns intelligently.

How to Extend Prisma Schema Using Antigravity
Overview
Learn how to leverage Antigravity's Prisma MCP integration to extend your database schema intelligently. This guide covers adding models, relations, migrations, and complex schema patterns with AI assistance.
Why Antigravity + Prisma?
Antigravity's Prisma MCP Server integration provides:
- Schema Awareness: Agent understands your current database structure
- Smart Suggestions: Proposes correct table and column names
- Relation Management: Handles complex many-to-many relationships
- Migration Generation: Creates safe database migrations
- Type Safety: Generates TypeScript types automatically
Prerequisites
- Existing Next.js project with Prisma
- Antigravity editor access
- PostgreSQL/MySQL/SQLite database
Connect Prisma MCP Server
Step 1: Open MCP Store
- Click "..." dropdown (top of agent panel)
- Select "MCP Store"
- Find "Prisma" in the list
- Click "Install"
Step 2: Authenticate
Follow the on-screen prompts to connect Prisma to your project.
Step 3: Verify Connection
The agent can now:
- Read your
prisma/schema.prisma - Understand existing models and relations
- Suggest schema extensions
- Generate migrations
Common Schema Extension Scenarios
1. Add a New Model
Scenario: Add a Comment model to blog posts
Prompt:
Add a Comment model to the Prisma schema with:
- id (UUID)
- content (Text)
- createdAt (DateTime)
- authorId (references User)
- postId (references Post)
- One-to-many relation: Post has many Comments
- One-to-many relation: User has many Comments
- Include cascade delete when post is deleted
Antigravity Response:
// prisma/schema.prisma
model Comment {
id String @id @default(uuid())
content String @db.Text
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
authorId String
author User @relation(fields: [authorId], references: [id])
postId String
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
@@index([postId])
@@index([authorId])
}
// Update Post model
model Post {
// ... existing fields
comments Comment[]
}
// Update User model
model User {
// ... existing fields
comments Comment[]
}
Migration Command:
npx prisma migrate dev --name add-comments
2. Add Many-to-Many Relation
Scenario: Posts can have multiple authors (collaboration)
Prompt:
Extend the Prisma schema to support multiple authors per post:
- Create many-to-many relation between User and Post
- Use explicit join table PostAuthor
- Include role field (AUTHOR, EDITOR, CONTRIBUTOR)
- Add createdAt timestamp
Antigravity Response:
model PostAuthor {
id String @id @default(uuid())
role AuthorRole @default(AUTHOR)
createdAt DateTime @default(now())
userId String
user User @relation(fields: [userId], references: [id])
postId String
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
@@unique([userId, postId])
@@index([userId])
@@index([postId])
}
enum AuthorRole {
AUTHOR
EDITOR
CONTRIBUTOR
}
model Post {
// ... existing fields
authors PostAuthor[]
}
model User {
// ... existing fields
authoredPosts PostAuthor[]
}
3. Add Enum Field
Scenario: Add post visibility levels
Prompt:
Add a visibility field to Post model:
- Enum type: PUBLIC, PRIVATE, UNLISTED
- Default to PUBLIC
- Add index for filtering
Antigravity Response:
enum PostVisibility {
PUBLIC
PRIVATE
UNLISTED
}
model Post {
// ... existing fields
visibility PostVisibility @default(PUBLIC)
@@index([visibility])
}
4. Add JSON Field
Scenario: Store flexible metadata
Prompt:
Add a metadata JSON field to Post:
- Store custom key-value pairs
- Optional field
- Use Prisma Json type
Antigravity Response:
model Post {
// ... existing fields
metadata Json?
}
Usage:
await prisma.post.create({
data: {
title: "Example Post",
metadata: {
featured: true,
readingTime: 5,
customField: "value"
}
}
});
5. Add Soft Delete
Scenario: Implement soft delete pattern
Prompt:
Add soft delete support to Post model:
- Add deletedAt DateTime field (nullable)
- Add deletedBy User relation (nullable)
- Exclude soft-deleted posts by default in queries
Antigravity Response:
model Post {
// ... existing fields
deletedAt DateTime?
deletedBy String?
deletedByUser User? @relation("DeletedPosts", fields: [deletedBy], references: [id])
@@index([deletedAt])
}
model User {
// ... existing relations
deletedPosts Post[] @relation("DeletedPosts")
}
Query helper:
// Exclude soft-deleted posts
const activePosts = await prisma.post.findMany({
where: { deletedAt: null }
});
// Include soft-deleted
const allPosts = await prisma.post.findMany();
// Only soft-deleted
const trashedPosts = await prisma.post.findMany({
where: { deletedAt: { not: null } }
});
6. Add Timestamps
Scenario: Track creation and updates
Prompt:
Add timestamp tracking to Category model:
- createdAt (auto-set on create)
- updatedAt (auto-update on change)
Antigravity Response:
model Category {
// ... existing fields
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
7. Add Unique Constraints
Scenario: Ensure email uniqueness
Prompt:
Add unique constraint to User email field
Add composite unique constraint on Post (userId, slug)
Antigravity Response:
model User {
email String @unique
// ... other fields
}
model Post {
userId String
slug String
@@unique([userId, slug])
}
8. Add Indexes
Scenario: Optimize query performance
Prompt:
Add indexes to Post model for:
- status field
- publishedAt field
- Composite index on (status, publishedAt)
- Full-text search on title and content
Antigravity Response:
model Post {
// ... existing fields
@@index([status])
@@index([publishedAt])
@@index([status, publishedAt])
@@fulltext([title, content])
}
9. Add Self-Referential Relation
Scenario: Nested categories (parent/child)
Prompt:
Make Category model hierarchical:
- Add parent-child relationship
- Category can have one parent
- Category can have many children
- Nullable parent (for root categories)
Antigravity Response:
model Category {
id String @id @default(uuid())
name String
parentId String?
// Self-referential relation
parent Category? @relation("CategoryHierarchy", fields: [parentId], references: [id])
children Category[] @relation("CategoryHierarchy")
@@index([parentId])
}
10. Add Polymorphic Relations
Scenario: Comments on multiple types (Posts, Videos)
Prompt:
Create a Comment model that can belong to either Post or Video:
- commentableType (POST or VIDEO)
- commentableId (UUID of either)
- Use discriminated union pattern
Antigravity Response:
enum CommentableType {
POST
VIDEO
}
model Comment {
id String @id @default(uuid())
content String @db.Text
commentableType CommentableType
commentableId String
authorId String
author User @relation(fields: [authorId], references: [id])
createdAt DateTime @default(now())
@@index([commentableType, commentableId])
}
// Usage in queries
const postComments = await prisma.comment.findMany({
where: {
commentableType: 'POST',
commentableId: postId
}
});
Advanced Schema Patterns
Auditing Pattern
Track who created and modified records:
Prompt:
Add audit fields to Post model:
- createdBy (User relation)
- updatedBy (User relation)
- Track creation and update authors
Antigravity Response:
model Post {
// ... existing fields
createdById String
createdBy User @relation("PostsCreated", fields: [createdById], references: [id])
updatedById String
updatedBy User @relation("PostsUpdated", fields: [updatedById], references: [id])
@@index([createdById])
@@index([updatedById])
}
model User {
// ... existing relations
postsCreated Post[] @relation("PostsCreated")
postsUpdated Post[] @relation("PostsUpdated")
}
Versioning Pattern
Keep history of changes:
Prompt:
Add versioning to Post model:
- version number (integer)
- PostVersion model to store history
- Track all changes with timestamps
Antigravity Response:
model Post {
// ... existing fields
version Int @default(1)
versions PostVersion[]
}
model PostVersion {
id String @id @default(uuid())
postId String
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
version Int
title String
content String @db.Text
createdAt DateTime @default(now())
createdBy String
author User @relation(fields: [createdBy], references: [id])
@@unique([postId, version])
@@index([postId])
}
Multi-Tenancy Pattern
Isolate data by organization:
Prompt:
Add multi-tenancy to the schema:
- Organization model
- All content models belong to Organization
- Add organizationId to Post, User, Category
Antigravity Response:
model Organization {
id String @id @default(uuid())
name String
slug String @unique
createdAt DateTime @default(now())
users User[]
posts Post[]
categories Category[]
}
model Post {
// ... existing fields
organizationId String
organization Organization @relation(fields: [organizationId], references: [id])
@@index([organizationId])
}
model User {
// ... existing fields
organizationId String
organization Organization @relation(fields: [organizationId], references: [id])
@@index([organizationId])
}
Migration Best Practices
1. Review Generated Migrations
Always check migrations before applying:
npx prisma migrate dev --name your-change --create-only
Review the SQL in prisma/migrations/:
-- CreateTable
CREATE TABLE "Comment" (
"id" TEXT NOT NULL PRIMARY KEY,
"content" TEXT NOT NULL,
"authorId" TEXT NOT NULL,
CONSTRAINT "Comment_authorId_fkey" FOREIGN KEY ("authorId")
REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateIndex
CREATE INDEX "Comment_authorId_idx" ON "Comment"("authorId");
Then apply:
npx prisma migrate dev
2. Handle Data Migrations
For schema changes affecting existing data:
Prompt:
I need to add a "featured" boolean field to Post model.
Existing posts should default to false.
Create a data migration to set the top 10 posts to featured=true.
Antigravity Response:
- Schema change:
model Post {
featured Boolean @default(false)
}
- Data migration script:
// prisma/migrations/20250120_set_featured_posts.ts
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function main() {
const topPosts = await prisma.post.findMany({
orderBy: { views: 'desc' },
take: 10,
});
await prisma.post.updateMany({
where: { id: { in: topPosts.map(p => p.id) } },
data: { featured: true },
});
console.log(`Set ${topPosts.length} posts as featured`);
}
main()
.catch(console.error)
.finally(() => prisma.$disconnect());
3. Rename Fields Safely
Prompt:
Rename Post.title to Post.headline
Preserve existing data
Antigravity Response:
- Create migration manually:
-- AlterTable
ALTER TABLE "Post" RENAME COLUMN "title" TO "headline";
- Update schema:
model Post {
headline String // formerly title
}
- Regenerate client:
npx prisma generate
4. Remove Fields Safely
Prompt:
Remove Post.oldField
Create backup before deletion
Antigravity Steps:
- Backup data:
// scripts/backup-old-field.ts
const posts = await prisma.post.findMany({
select: { id: true, oldField: true }
});
fs.writeFileSync('backup-oldField.json', JSON.stringify(posts));
- Remove from schema:
model Post {
// oldField removed
}
- Create migration:
npx prisma migrate dev --name remove-old-field
Troubleshooting
Foreign Key Constraint Errors
Error: "Foreign key constraint failed"
Solution via Antigravity:
Update the schema to add onDelete cascade to the Comment relation:
Comment.postId -> Post.id (onDelete: Cascade)
This ensures comments are deleted when posts are deleted.
Result:
model Comment {
postId String
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
}
Unique Constraint Violations
Error: "Unique constraint failed on slug"
Solution via Antigravity:
Add validation in the application layer to check slug uniqueness
before creating posts:
async function createPost(data) {
let slug = slugify(data.title);
let counter = 1;
while (await prisma.post.findUnique({ where: { slug } })) {
slug = `${slugify(data.title)}-${counter}`;
counter++;
}
return prisma.post.create({
data: { ...data, slug }
});
}
Migration Conflicts
Error: "Migration conflicts detected"
Solution:
I have migration conflicts. Help me resolve them.
Current state: My local migrations differ from production
Antigravity Response:
- Check migration history:
npx prisma migrate status
- If behind production:
npx prisma migrate deploy
- If ahead of production:
npx prisma migrate resolve --rolled-back 20250120_migration_name
- If diverged:
npx prisma migrate diff \
--from-schema-datamodel prisma/schema.prisma \
--to-schema-datasource prisma/schema.prisma
Testing Schema Changes
1. Test Migrations Locally
# Create test database
createdb myapp_test
# Run migrations
DATABASE_URL="postgresql://localhost/myapp_test" \
npx prisma migrate dev
# Seed test data
npx prisma db seed
# Test queries
npm test
2. Validate Relations
Prompt:
Test the Comment -> Post relation by:
1. Creating a post
2. Creating comments for that post
3. Querying post with comments
4. Deleting post and verify comments cascade delete
Antigravity Response:
// test/post-comments.test.ts
import { prisma } from '@/lib/prisma';
describe('Post Comments Relation', () => {
let post: Post;
beforeAll(async () => {
post = await prisma.post.create({
data: {
title: 'Test Post',
content: 'Content',
}
});
});
it('creates comments for post', async () => {
const comment = await prisma.comment.create({
data: {
content: 'Test comment',
postId: post.id,
authorId: testUser.id,
}
});
expect(comment.postId).toBe(post.id);
});
it('queries post with comments', async () => {
const postWithComments = await prisma.post.findUnique({
where: { id: post.id },
include: { comments: true }
});
expect(postWithComments.comments.length).toBeGreaterThan(0);
});
it('cascade deletes comments when post deleted', async () => {
const commentCount = await prisma.comment.count({
where: { postId: post.id }
});
await prisma.post.delete({ where: { id: post.id } });
const remainingComments = await prisma.comment.count({
where: { postId: post.id }
});
expect(remainingComments).toBe(0);
});
});
Real-World Examples
E-commerce Schema
Prompt:
Extend my schema for an e-commerce platform:
- Product model with variants
- Order model with order items
- Cart model
- Payment model
- Shipping address
- Include all necessary relations
Antigravity generates:
model Product {
id String @id @default(uuid())
name String
description String @db.Text
price Decimal @db.Decimal(10, 2)
stock Int @default(0)
variants ProductVariant[]
orderItems OrderItem[]
createdAt DateTime @default(now())
}
model ProductVariant {
id String @id @default(uuid())
productId String
product Product @relation(fields: [productId], references: [id])
name String // e.g., "Size: Large, Color: Blue"
price Decimal @db.Decimal(10, 2)
stock Int
sku String @unique
}
model Cart {
id String @id @default(uuid())
userId String @unique
user User @relation(fields: [userId], references: [id])
items CartItem[]
createdAt DateTime @default(now())
}
model CartItem {
id String @id @default(uuid())
cartId String
cart Cart @relation(fields: [cartId], references: [id])
productId String
product Product @relation(fields: [productId], references: [id])
quantity Int @default(1)
}
model Order {
id String @id @default(uuid())
userId String
user User @relation(fields: [userId], references: [id])
items OrderItem[]
total Decimal @db.Decimal(10, 2)
status OrderStatus @default(PENDING)
shippingAddress ShippingAddress?
payment Payment?
createdAt DateTime @default(now())
}
model OrderItem {
id String @id @default(uuid())
orderId String
order Order @relation(fields: [orderId], references: [id])
productId String
product Product @relation(fields: [productId], references: [id])
quantity Int
price Decimal @db.Decimal(10, 2)
}
model ShippingAddress {
id String @id @default(uuid())
orderId String @unique
order Order @relation(fields: [orderId], references: [id])
street String
city String
state String
zipCode String
country String
}
model Payment {
id String @id @default(uuid())
orderId String @unique
order Order @relation(fields: [orderId], references: [id])
amount Decimal @db.Decimal(10, 2)
status PaymentStatus @default(PENDING)
method String // e.g., "credit_card", "paypal"
transactionId String?
paidAt DateTime?
}
enum OrderStatus {
PENDING
PAID
SHIPPED
DELIVERED
CANCELLED
}
enum PaymentStatus {
PENDING
COMPLETED
FAILED
REFUNDED
}
Next Steps
You've mastered Prisma schema extensions with Antigravity! Now explore:
- Build APIs: How to Create API Routes with Antigravity
- CRUD Operations: How to Build CRUD with Antigravity
- Best Practices: Antigravity Best Practices
- Example Projects: Antigravity Projects Examples
Conclusion
Antigravity's Prisma MCP integration makes schema extension intelligent and safe:
- Understands your existing structure
- Suggests proper relations
- Generates migrations automatically
- Prevents common mistakes
Start extending your Prisma schema with AI assistance today!
Keywords: antigravity prisma example, extend prisma schema antigravity, prisma schema tutorial, antigravity database, prisma migrations antigravity, prisma relations