Upgrade Prisma ORM

Upgrade to v1

Comprehensive guide for upgrading from Prisma 1 to Prisma ORM v1

This guide provides a comprehensive roadmap for migrating your project from Prisma 1 to the latest version of Prisma ORM. The migration process involves significant architectural changes and requires careful planning and execution.

Before you begin

  • Back up your database before starting the migration
  • Review the Prisma ORM documentation to understand the new architecture
  • Set up a separate development environment for testing the migration
  • Document your current Prisma 1 setup, including models, relations, and any custom configurations

Key changes

Architectural changes

FeaturePrisma 1Prisma ORM
Database ConnectionUses Prisma Server as a proxyDirect database connection
APIGraphQL API for databaseProgrammatic access via Prisma Client
SchemaGraphQL SDL + prisma.ymlUnified Prisma schema
ModelingGraphQL SDLPrisma Schema Language (PSL)
Workflowprisma deployprisma migrate and prisma db commands

Feature changes

  • Removed: GraphQL API for database
  • New: Type-safe database client
  • Improved: Database introspection and migration tools
  • Enhanced: Support for more database features and types

Migration Strategy

1. Preparation

Install Prisma ORM

# Initialize a new project
npm init -y
npm install prisma @prisma/client

# Initialize Prisma
npx prisma init

Set up Database Connection

Update the DATABASE_URL in your .env file to point to your existing database:

DATABASE_URL="postgresql://user:password@localhost:5432/your_database?schema=public"

2. Schema Migration

Introspect Database

npx prisma db pull

This will generate a schema.prisma file based on your existing database schema.

Update Schema

After introspection, you'll need to make several adjustments to the schema:

Default Values
// Before (Prisma 1)
model User {
  id        String   @default(cuid())
  email     String   @unique
  name      String?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
Relations
// Before (Prisma 1)
type Post {
  id        ID!      @id
  title     String!
  author    User!    @relation(name: "UserPosts")
}

// After (Prisma ORM)
model Post {
  id        Int      @id @default(autoincrement())
  title     String
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
}

3. Data Model Adjustments

3.1 Handling Special Types

Prisma 1 TypePrisma ORM EquivalentNotes
IDString @id @default(cuid())Add @id directive
DateTimeDateTimeNo change needed
JsonJsonNo change needed
EnumEnumDefine enums in the schema

3.2 Relation Handling

Prisma ORM requires explicit relation fields and foreign keys:

model User {
  id    Int     @id @default(autoincrement())
  posts Post[]
}

model Post {
  id       Int    @id @default(autoincrement())
  title    String
  author   User   @relation(fields: [authorId], references: [id])
  authorId Int
}

4. Update Application Code

4.1 Replace Prisma 1 Client with Prisma Client

// Before (Prisma 1)
import { prisma } from './generated/prisma-client';

async function getUser(id: string) {
  return prisma.user({ id });
}

// After (Prisma ORM)
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();

async function getUser(id: number) {
  return prisma.user.findUnique({
    where: { id }
  });
}

4.2 Update Queries and Mutations

Fetching Data
// Before (Prisma 1)
const user = await prisma.user({ id: 1 });
const posts = await prisma.user({ id: 1 }).posts();

// After (Prisma ORM)
const user = await prisma.user.findUnique({
  where: { id: 1 },
  include: { posts: true }
});
const posts = user?.posts;
Creating Records
// Before (Prisma 1)
const newUser = await prisma.createUser({
  name: 'Alice',
  email: 'alice@example.com'
});

// After (Prisma ORM)
const newUser = await prisma.user.create({
  data: {
    name: 'Alice',
    email: 'alice@example.com'
  }
});

Testing and Validation

1. Test Data Operations

Test all CRUD operations to ensure data consistency:

// Test create
const user = await prisma.user.create({
  data: { name: 'Test', email: 'test@example.com' }
});

// Test read
const foundUser = await prisma.user.findUnique({
  where: { id: user.id }
});

// Test update
const updatedUser = await prisma.user.update({
  where: { id: user.id },
  data: { name: 'Updated Name' }
});

// Test delete
await prisma.user.delete({
  where: { id: user.id }
});

2. Test Relations

Verify that all relations work as expected:

// Test relation queries
const userWithPosts = await prisma.user.findUnique({
  where: { id: 1 },
  include: {
    posts: true,
    profile: true
  }
});

// Test nested writes
const userWithNewPost = await prisma.user.create({
  data: {
    name: 'Bob',
    email: 'bob@example.com',
    posts: {
      create: {
        title: 'Hello World',
        content: 'This is my first post'
      }
    }
  },
  include: {
    posts: true
  }
});

Handling Special Cases

1. Real-time Subscriptions

Prisma ORM doesn't include built-in real-time subscriptions. Consider these alternatives:

Option 1: Database Triggers

-- PostgreSQL example
CREATE OR REPLACE FUNCTION notify_new_post()
RETURNS TRIGGER AS $$
BEGIN
  PERFORM pg_notify('new_post', row_to_json(NEW)::text);
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER new_post_trigger
AFTER INSERT ON "Post"
FOR EACH ROW EXECUTE FUNCTION notify_new_post();

Option 2: Application-Level Events

// Publish event when creating a post
const post = await prisma.post.create({
  data: {
    title: 'New Post',
    content: 'Content',
    author: { connect: { id: userId }}
  }
});

// Publish event to your pub/sub system
await pubsub.publish('POST_CREATED', { postCreated: post });

2. Authentication

If you were using Prisma 1's built-in authentication, you'll need to implement your own solution:

import { compare } from 'bcryptjs';
import { sign } from 'jsonwebtoken';

export async function login(email: string, password: string) {
  const user = await prisma.user.findUnique({ where: { email } });
  if (!user) throw new Error('User not found');
  
  const valid = await compare(password, user.password);
  if (!valid) throw new Error('Invalid password');
  
  const token = sign({ userId: user.id }, process.env.APP_SECRET!);
  return { token, user };
}

Migration Tools

Prisma 1 Upgrade CLI

The Prisma 1 Upgrade CLI can help automate parts of the migration:

# Install the upgrade CLI
npm install -g prisma1-upgrade

# Run the upgrade helper
prisma1-upgrade

This tool helps with:

  • Converting your Prisma 1 datamodel to Prisma schema
  • Identifying potential issues in your schema
  • Providing migration recommendations

Performance Considerations

  1. Connection Pooling: Configure connection pooling for better performance:

    const prisma = new PrismaClient({
      log: ['query', 'info', 'warn', 'error'],
      datasources: {
        db: {
          url: process.env.DATABASE_URL + '&connection_limit=20'
        }
      }
    });
  2. Query Optimization: Use select to fetch only needed fields:

    const user = await prisma.user.findUnique({
      where: { id: 1 },
      select: {
        id: true,
        name: true,
        email: true
      }
    });

Next Steps

Getting Help

If you encounter issues during migration:

  1. Search the GitHub Issues
  2. Ask for help in the Prisma Slack
  3. Open a GitHub Discussion

On this page