Skip to content

Use Prisma ORM with Appwrite Postgres_

Model your data with Prisma ORM, generate a typed client, and test schema migrations against Appwrite Postgres.

ORMs are a popular way to work with database records as objects in application code. With Appwrite Postgres, you can use Prisma ORM to describe your data in a schema file and generate a TypeScript client for it.

This guide uses a small reading list to put that workflow into practice. You'll save bookmarks, query unread links, and add priorities through a migration. The database runs on Appwrite Cloud, while Prisma ORM handles the models, queries, and migration files.

Provision Postgres

Open your project at appwrite.io, then choose Databases → Create database. Select PostgreSQL under Native databases.

The PostgreSQL option under Native databases
The PostgreSQL option under Native databases

Name the database Reading list, keep the automatically generated ID, and choose Starter. Leave replicas and PITR off for this example. Review the configuration and price, then click Create database. The PostgreSQL quick start covers the available options.

Once provisioning finishes, the SQL editor opens. The sidebar gives you access to your tables and connection credentials.

The Reading list database workspace in Appwrite
The Reading list database workspace in Appwrite

Configure Prisma ORM

Open Credentials, select DSN, and copy the connection string.

Connection credentials for the Reading list database with the password hidden
Connection credentials for the Reading list database with the password hidden

This example uses Prisma ORM 7. Install the client, PostgreSQL adapter, and CLI in your TypeScript project:

Bash
npm install @prisma/client@7.10.0 @prisma/adapter-pg@7.10.0 dotenv pg
npm install --save-dev prisma@7.10.0 typescript tsx @types/node @types/pg
npx prisma init --datasource-provider postgresql --output ../generated/prisma

Use "type": "module" in package.json. In .env, set DATABASE_URL to the copied connection string with port 5432. We use this direct endpoint for migrations because they can depend on a consistent database session. Port 6432 uses the connection pooler. Keep the other connection values and TLS settings unchanged, and keep .env out of Git. See connection options.

.env
DATABASE_URL="postgresql://<USER>:<PASSWORD>@<HOST>:5432/<DATABASE>?sslmode=require"

Update the generated prisma7.config.ts:

TypeScript
import "dotenv/config";
import { defineConfig, env } from "prisma/config";
export default defineConfig({
schema: "prisma/schema.prisma",
migrations: { path: "prisma/migrations" },
datasource: {
url: env("DATABASE_URL"),
},
});

Describe the bookmarks

Prisma ORM models live in prisma/schema.prisma. Each model defines fields and constraints that Prisma Migrate translates into a database table. Replace the generated schema with:

Plain text
generator client {
provider = "prisma-client"
output = "../generated/prisma"
}
datasource db {
provider = "postgresql"
}
model Bookmark {
id Int @id @default(autoincrement())
title String
url String @unique
read Boolean @default(false)
@@map("bookmarks")
}

@unique prevents duplicate URLs. @default(false) makes new bookmarks unread, and @@map("bookmarks") gives the table a lowercase name while keeping the client API as prisma.bookmark.

Generate SQL for the empty database and save it as the first migration:

Bash
mkdir -p prisma/migrations/0001_create_bookmarks
npx prisma migrate diff \
--from-empty \
--to-schema prisma/schema.prisma \
--script \
--output prisma/migrations/0001_create_bookmarks/migration.sql

Review migration.sql, then apply it and generate Prisma Client:

Bash
npx prisma migrate deploy
npx prisma generate

migrate diff produces SQL, migrate deploy applies pending migrations, and generate builds the client from your model. Commit prisma/migrations with your schema and configuration so other environments can apply the same changes.

In Appwrite, choose Data → public, refresh the table list, and open bookmarks → Columns. The table should have id, title, url, and read.

The bookmarks table with the four fields from the Prisma ORM model
The bookmarks table with the four fields from the Prisma ORM model

Save and query bookmarks

Create src/db.ts to connect the generated client to Postgres through the driver adapter:

TypeScript
import "dotenv/config";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "../generated/prisma/client";
const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL! });
export const prisma = new PrismaClient({ adapter });

The following examples are standalone scripts, so they disconnect when finished. In a server application, reuse Prisma Client across requests and disconnect at shutdown.

Create src/bookmarks.ts:

TypeScript
import { prisma } from "./db";
try {
await prisma.bookmark.createMany({
data: [
{
title: "Postgres quick start",
url: "https://appwrite.io/docs/products/databases/postgresql/quick-start",
},
{
title: "Prisma ORM integration",
url: "https://appwrite.io/docs/products/databases/postgresql/integrations/prisma",
},
{
title: "Database branches",
url: "https://appwrite.io/docs/products/databases/postgresql/branches",
},
],
skipDuplicates: true,
});
const unread = await prisma.bookmark.findMany({
where: { read: false },
select: { title: true, url: true },
orderBy: { title: "asc" },
});
console.table(unread);
} finally {
await prisma.$disconnect();
}

Run npx tsx src/bookmarks.ts. The result lists Database branches, Postgres quick start, and Prisma ORM integration in title order. Running the script again skips the existing URLs. The where, select, and orderBy options are typed from your model.

Add priorities with a migration

Add this field to Bookmark in prisma/schema.prisma:

Plain text
priority Int @default(0)

Compare the database with your updated model and save the next migration:

Bash
mkdir -p prisma/migrations/0002_add_priority
npx prisma migrate diff \
--from-config-datasource \
--to-schema prisma/schema.prisma \
--script \
--output prisma/migrations/0002_add_priority/migration.sql

Open the new migration.sql under prisma/migrations. It adds the column with a default for existing bookmarks:

SQL
ALTER TABLE "bookmarks" ADD COLUMN "priority" INTEGER NOT NULL DEFAULT 0;

Apply the migration and regenerate the client so its types include priority:

Bash
npx prisma migrate deploy
npx prisma generate

Refresh Columns in Appwrite. The new priority column has a default of 0, and the three bookmarks are still present.

The bookmarks table after adding the priority column
The bookmarks table after adding the priority column

Choose what to read next

Create src/prioritize.ts to mark the quick start as read and move the Prisma ORM integration to the top of the remaining list:

TypeScript
import { prisma } from "./db";
try {
await prisma.bookmark.update({
where: {
url: "https://appwrite.io/docs/products/databases/postgresql/quick-start",
},
data: { read: true },
});
await prisma.bookmark.update({
where: {
url: "https://appwrite.io/docs/products/databases/postgresql/integrations/prisma",
},
data: { priority: 2 },
});
const next = await prisma.bookmark.findMany({
where: { read: false },
select: { title: true, priority: true },
orderBy: [{ priority: "desc" }, { title: "asc" }],
});
console.table(next);
} finally {
await prisma.$disconnect();
}

Run npx tsx src/prioritize.ts. Prisma ORM integration appears first with priority 2, followed by Database branches with priority 0. Postgres quick start is excluded because it is marked as read.

Open Rows in Appwrite and refresh to inspect the saved values.

Saved bookmarks with the quick start marked as read and the Prisma ORM integration prioritized
Saved bookmarks with the quick start marked as read and the Prisma ORM integration prioritized

Bring the model into your application

Prisma ORM gives you a query API generated from your schema, with types that help catch invalid fields and values during development. Prisma Migrate keeps database changes in SQL files you can review and deploy alongside the application code that uses them.

You can use the same approach in a production application backed by Appwrite Postgres. Test changes against an isolated database branch, then apply committed migrations during deployment with npx prisma migrate deploy.

Resources

Read next

Ready to build?_