Using Prisma
Prisma is a popular open-source TypeScript ORM. The main idea is to define your application data models (entities) in the Prisma Schema, and then use Prisma to automatically generate schema migrations as well as the corresponding Prisma Client for you to manage your data. DBOS supports Prisma as an alternative to Knex and TypeORM for transactional data management.
Getting Started
An easy way to get started with Prisma is to bootstrap your application with our Prisma template. This is similar to the template used in the quickstart, but built with Prisma instead of Knex. To download it, run:
npx -y @dbos-inc/create@latest -t hello-prisma -n <app-name>
Then, build it, run schema migrations, and start the Prisma sample app:
npm run build
npx dbos migrate
npx dbos start
To see that it's working, visit this URL in your browser: http://localhost:3000/greeting/dbos. You should get this message: Greeting 1: Hello, dbos!
Each time you refresh the page, the counter should go up by one.
Setting Up Prisma Schema
In DBOS, the Prisma Schema is defined in the same way as any other Prisma project.
In this tutorial we assume it is located at the default path (prisma/schema.prisma
), for example:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model DbosHello {
@@map("dbos_hello")
greeting_id Int @id @default(autoincrement())
greeting String
}
Note that the schema file requires a $DATABASE_URL
environment variable to connect to a database. To make it easy, we include in our template a script to automatically generate a prisma/.env
file with the correct database URL constructed from your dbos-config.yaml
file.
Schema Management
In production scenarios or when using DBOS Cloud, we strongly recommend you manage your database schema using Prisma Migrate. To update your database schema, you first need to edit your Prisma schema file, and then create a new migration by running:
npx prisma migrate dev --name <migration_name>
This automatically generates a new migration (under prisma/migrations/
) containing SQL commands to transition your database from its current schema to the schema defined in your latest Prisma schema.
Using Prisma
When using DBOS, database operations are performed in transaction functions. Transaction functions must be annotated with the @Transaction
decorator and must have a TransactionContext<PrismaClient>
as their first argument.
Note that we specify PrismaClient
in angle brackets.
Within the transaction function, access your Prisma client from the .client
field of your transaction context.
For example:
import { PrismaClient } from "@prisma/client";
export class Hello {
@Transaction()
static async helloTransaction(txnCtxt: TransactionContext<PrismaClient>, name: string) {
const greeting = `Hello, ${name}!`;
const res = await txnCtxt.client.dbosHello.create({
data: {
greeting: greeting,
},
});
return `Greeting ${res.greeting_id}: ${greeting}`;
}
}
Configuring Prisma
If you are using the Prisma template, this is done for you.
To enable Prisma, you must set the app_db_client
field in the DBOS configuration file to prisma
.
You should also configure Prisma migration commands.
Here is an example of a configuration file set up for Prisma:
language: node
database:
hostname: 'localhost'
port: 5432
username: 'postgres'
password: ${PGPASSWORD}
connectionTimeoutMillis: 3000
app_db_client: prisma
migrate:
- npx prisma migrate deploy
Prisma doesn't support schema migration rollback for successfully applied migrations like other ORMs.
Therefore, we omit the rollback
configuration here.
See the Prisma documentation on rolling back schema changes.
Many Prisma commands, such as those for schema migrations, require a DATABASE_URL
environment variable to be correctly set.
To avoid managing your configuration in two places, we recommend using this script to automatically generate a prisma/.env
file with the correct DATABASE_URL
string constructed from your DBOS config:
const { parseConfigFile } = require('@dbos-inc/dbos-sdk/dist/src/dbos-runtime/config');
const fs = require('node:fs');
const path = require('node:path');
// Load the configuration file
const [dbosConfig, ] = parseConfigFile();
// Write out the .env file
const databaseURL = `postgresql://${dbosConfig.poolConfig.user}:${dbosConfig.poolConfig.password}@${dbosConfig.poolConfig.host}:${dbosConfig.poolConfig.port}/${dbosConfig.poolConfig.database}`;
try {
fs.writeFileSync(path.join(process.cwd(), 'prisma', '.env'), `DATABASE_URL="${databaseURL}"`);
console.log("Wrote database URL to the prisma/.env file.");
} catch (error) {
console.error("Error writing prisma/.env file:", error.message);
}
You also need to generate a Prisma Client from your Prisma schema before compiling your application.
Therefore, we recommend that you set the build script in your package.json
file as follows:
{
"scripts": {
"build": "node generate_env.js && npx prisma generate && tsc"
}
}
Known Issues
- Currently we do not support time travel debugging for cloud deployed Prisma applications. However, you can still perform interactive time travel queries.