Prisma is a modern TypeScript ORM that provides type-safe database access and migrations. With Prisma, you define your database schema in a schema.prisma file and use Prisma's CLI to generate SQL migrations and a TypeScript client.
This guide explains how to integrate Prisma with Encore.ts, leveraging Encore's built-in database management while using Prisma's powerful ORM features.
Prisma generates the migration files and TypeScript client
Encore manages database creation, connections, and applies migrations
You use Encore's SQLDatabase to provide connection strings to Prisma
The key to this integration is configuring Prisma to use Encore's shadow database for its operations, preventing any conflicts between the two systems.
Here's a complete example of using Prisma with Encore.ts:
users/database.ts
users/prisma/schema.prisma
users/prisma/client.ts
users/api.ts
import { SQLDatabase } from"encore.dev/storage/sqldb";
// Define a database named 'users', using the database migrations// in the "./prisma/migrations" folder (generated by Prisma).exportconstDB = newSQLDatabase("users", {
migrations: {
path: "./prisma/migrations",
source: "prisma",
},
});
users/prisma/schema.prisma
generator client {
provider = "prisma-client"
output = "./generated"
previewFeatures = ["queryCompiler", "driverAdapters"]
}
datasource db {
provider = "postgresql"
// Connect Prisma CLI to Encore's shadow database
// This prevents interference with Encore's migration system
url = env("SHADOW_DB_URL")
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String
createdAt DateTime @default(now())
}
users/prisma/client.ts
import { PrismaClient } from "./generated/client";
import { PrismaPg } from "@prisma/adapter-pg";
import { DB } from "../database";
// Create and export the Prisma client instance
export const prisma = new PrismaClient({
adapter: new PrismaPg({ connectionString: DB.connectionString }),
});
// Re-export types from the generated client
export * from "./generated/client";
users/api.ts
import { api } from "encore.dev/api";
import { prisma } from "./prisma/client";
interface CreateUserRequest {
email: string;
name: string;
}
// Example API endpoint using Prisma
export const createUser = api(
{ method: "POST", path: "/users", expose: true },
async (req: CreateUserRequest) => {
const user = await prisma.user.create({
data: req,
});
return user;
}
);
Create database.ts to define your Encore database:
database.ts
import { SQLDatabase } from"encore.dev/storage/sqldb";
// Export the database so it can be used in the Prisma clientexportconstDB = newSQLDatabase("myapp", {
migrations: {
path: "./prisma/migrations",
source: "prisma",
},
});
Run encore run to create the database (make sure the migrations folder has been created first).
Prisma needs to connect to Encore's shadow database for migration operations. The shadow database is a temporary database that Prisma uses to detect schema drift and generate migrations without affecting your main database.
Get the connection strings:
# Main database connection (for Prisma Studio)
encore db conn-uri myapp
# Shadow database connection (for Prisma CLI operations)
encore db conn-uri myapp --shadow
Create a .env file in your project root:
# Connection strings for local developmentDB_URL=<main-database-connection-string>
SHADOW_DB_URL=<shadow-database-connection-string>
generator client {
provider = "prisma-client"output = "./generated"previewFeatures = ["queryCompiler", "driverAdapters"]
}
datasource db {
provider = "postgresql"
// IMPORTANT: Use shadow database URL for Prisma CLI operations
url = env("SHADOW_DB_URL")
}
// Define your models here
model User {
id Int @id @default(autoincrement())
email String @unique
name String
}