---
layout: post
title: Use Prisma ORM with Appwrite Postgres
description: Model your data with Prisma ORM, generate a typed client, and test schema migrations against Appwrite Postgres.
date: 2026-09-08
cover: /images/blog/prisma-orm-appwrite-postgres/cover.avif
timeToRead: 8
author: atharva
category: tutorial
featured: false
faqs:
  - question: "Can I use Prisma ORM with Appwrite Postgres?"
    answer: "Yes. Appwrite Postgres accepts standard PostgreSQL connections. Use Prisma ORM with the PostgreSQL driver adapter to query your database through a generated TypeScript client."
  - question: "How do I apply Prisma ORM schema changes to Appwrite Postgres?"
    answer: "Generate SQL from your model changes with Prisma Migrate, then review and commit the migration files. Apply them with npx prisma migrate deploy through the direct connection on port 5432."
  - question: "When should I regenerate Prisma Client?"
    answer: "Run npx prisma generate after changing your Prisma schema so the generated client includes the updated models and fields. Applying a SQL migration and generating the client are separate steps in this guide."
---

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](https://appwrite.io), then choose **Databases → Create database**. Select **PostgreSQL** under **Native databases**.

![The PostgreSQL option under Native databases](/images/blog/prisma-orm-appwrite-postgres/provision-postgres.avif)

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](/docs/products/databases/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](/images/blog/prisma-orm-appwrite-postgres/database-workspace.avif)

# Configure Prisma ORM

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

![Connection credentials for the Reading list database with the password hidden](/images/blog/prisma-orm-appwrite-postgres/database-credentials.avif)

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

```sh
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](/docs/products/databases/postgresql/connections).

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

Update the generated `prisma7.config.ts`:

```ts
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](https://www.prisma.io/docs/orm/prisma-schema/overview) live in `prisma/schema.prisma`. Each model defines fields and constraints that Prisma Migrate translates into a database table. Replace the generated schema with:

```prisma
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:

```sh
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:

```sh
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](/images/blog/prisma-orm-appwrite-postgres/bookmarks-created.avif)

# Save and query bookmarks

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

```ts
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`:

```ts
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`:

```prisma
priority Int @default(0)
```

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

```sh
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`:

```sh
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](/images/blog/prisma-orm-appwrite-postgres/bookmarks-priority.avif)

# 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:

```ts
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](/images/blog/prisma-orm-appwrite-postgres/bookmarks-rows.avif)

# 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](/docs/products/databases/postgresql/branches), then apply committed migrations during deployment with `npx prisma migrate deploy`.

# Resources

- [Prisma ORM integration guide](/docs/products/databases/postgresql/integrations/prisma)
- [PostgreSQL quick start](/docs/products/databases/postgresql/quick-start)
- [Database branches](/docs/products/databases/postgresql/branches)
- [Discord community](https://appwrite.io/discord)
