Skip to main content
Version: 3.0 Beta

Migrating From Prisma

Overview​

This guide will help you migrate an existing Prisma project to ZenStack v3. The process is made straightforward by the following design decisions:

  1. The ZModel schema language is a superset of Prisma Schema Language.
  2. The ORM provides a Prisma-compatible API.
  3. The migration engine is built on top of Prisma Migrate.

In the following sections, we'll cover various aspects of the migration process where care needs to be taken.

warning

ZenStack v3 currently only supports PostgreSQL and SQLite databases.

Migration Steps​

1. Project dependencies​

ZenStack v3 doesn't depend on Prisma at runtime. Its CLI has a peer dependency on the prisma package for migration related commands. The most straightforward way is to follow these steps:

  • Remove prisma and @prisma/client from your project dependencies.

  • Install ZenStack packages

    npm install --save-dev @zenstackhq/cli@next
    npm install @zenstackhq/runtime@next
  • Install a database driver

    ZenStack doesn't bundle database drivers. Install the appropriate driver for your database:

    npm install --save-dev @types/pg
    npm install pg

You don't need to explicitly install prisma package because the @zenstackhq/cli has a peer dependency on it.

2. Migrate your schema​

If you have a single schema.prisma file, you can move and rename it to zenstack/schema.zmodel. No change should be necessary because every valid Prisma schema is also a valid ZModel schema. The only optional change you can consider making is to remove the Prisma client generator block since it doesn't have any effect in ZenStack:

generator client {
provider = "prisma-client-js"
}

If you use Prisma's multi-schema feature, you'll need to explicitly use the import statement to merge related schema files into a whole graph. See Multi-file Schema for details.

3. Update generation command​

In your package.json scripts, replace the prisma generate command with zen generate.

{
"scripts": {
"generate": "zen generate"
}
}

4. Update database client instantiation​

Replace new PrismaClient() with new ZenStackClient(schema, ...) where schema is imported from the TypeScript code generated by the zen generate command.

db.ts
import { ZenStackClient } from '@zenstackhq/runtime';
import { schema } from './zenstack/schema';
import { PostgresDialect } from 'kysely';
import { Pool } from 'pg';

export const db = new ZenStackClient(schema, {
dialect: new PostgresDialect({
pool: new Pool({
connectionString: process.env.DATABASE_URL,
}),
}),
});

Since ZenStackClient has a PrismaClient-compatible API, you should not need to change your existing code that uses the database client.

5. Update type references​

Prisma generates many TypeScript types that you may have used in your code, such as User, UserCreateArgs, etc. ZenStack replicates some of the most useful types in its generated code.

For top-level model types like User, you can import from the models.ts file. For other detailed input types like UserCreateArgs, import them from the input.ts file.

6. Update migration command​

In your package.json scripts, replace the Prisma db and migrate commands with ZenStack equivalents:

{
"scripts": {
"db:push": "zen db push",
"migrate:dev": "zen migrate dev",
"migrate:deploy": "zen migrate deploy"
}
}

Other Considerations​

Now, let's check the areas that are less straightforward to migrate.

Prisma custom generators​

ZenStack has its own CLI plugin system and doesn't support Prisma custom generators. However, you can continue running them with the following two steps:

  1. Use the @core/prisma plugin to generate a Prisma schema from ZModel.

    plugin prisma {
    provider = '@core/prisma'
    output = './schema.prisma'
    }
  2. Run a prisma generate command after zen generate with the prisma schema as input.

    {
    "scripts": {
    "generate": "zen generate && prisma generate --schema=zenstack/schema.prisma"
    }
    }

Prisma client extensions​

ZenStack has its own runtime plugin mechanism and doesn't plan to be compatible with Prisma client extensions. However, there are easy migration paths for the two most popular types of Prisma client extensions.

1. Query extension

Query extension allows you to intercept ORM query calls.

Suppose you have an extension like:

const extPrisma = prisma.$extends({
query: {
user: {
async findMany({ model, operation, args, query }) {
// take incoming `where` and set `age`
args.where = { ...args.where, age: { gt: 18 } }
return query(args)
},
},
},
});

You can replace it with an equivalent ZenStack plugin:

const extDb = db.$use({
id: 'my-plugin',
onQuery: {
user: {
async findMany({ model, operation, args, proceed }) {
// take incoming `where` and set `age`
args.where = { ...args.where, age: { gt: 18 } }
return proceed(args)
},
},
},
});

You can also use the special $allModels and $allOperations keys to apply the plugin to all models and operations, like when using Prisma client extensions.

2. Result extension

Result extension allows you to add custom fields to query results. ZenStack provides a mechanism that achieves the same goal but a lot more powerful.

Suppose you have a result extension like:

const extPrisma = prisma.$extends({
result: {
user: {
fullName: {
// the dependencies
needs: { firstName: true, lastName: true },
compute(user) {
// the computation logic
return `${user.firstName} ${user.lastName}`
},
},
},
},
});

You can replace it with a ZenStack computed field, which involves changes in ZModel and database client instantiation.

zenstack/schema.zmodel
model User {
...
firstName String
lastName String
fullName String @computed
}
export const db = new ZenStackClient(schema, {
...,
computedFields: {
User: {
// SQL: CONCAT(firstName, ' ', lastName)
fullName: (eb) => eb.fn('concat', ['firstName', eb.val(' '), 'lastName'])
},
},
});

A key difference is that ZenStack's computed fields are evaluated on the database side, which much more efficient and flexible than client-side computation. Read more in the Computed Fields documentation.

Feature Gap​

Here's a list of Prisma features that are not supported in ZenStack v3:

FeaturePlannedNotes
Client ExtensionsNoReplaced with ZenStack runtime plugins
JSON FiltersYes
Full-Text SearchYes
Comparing ColumnsYes
Postgres Multi-SchemaYes
Comments
Feel free to ask questions, give feedback, or report issues.

Don't Spam


You can edit/delete your comments by going directly to the discussion, clicking on the 'comments' link below