# Add Prisma ORM and PostgreSQL to an existing app (/docs/prisma-orm/quickstart/existing-app/postgresql) > For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL. Add Prisma ORM to an app you already have, create the tables in an empty PostgreSQL database, run a first query, and apply a first migration. Location: Prisma ORM > Quickstart > Existing App > Add Prisma ORM and PostgreSQL to an existing app This page uses PostgreSQL. [Use MongoDB instead](https://www.prisma.io/docs/prisma-orm/quickstart/existing-app/mongodb). Use this page when you already have an app and its database has no tables yet. By the end, your app has one model, the database has a table for it, and a script writes and reads a row. You also change the model once and apply the change to the database with a migration. If your database already has tables, follow [Add Prisma ORM to an existing PostgreSQL database](https://www.prisma.io/docs/prisma-orm/add-to-existing-project/postgresql) instead. If your app uses Prisma ORM 7 today, follow [Prisma ORM 7 to 8 (PostgreSQL)](https://www.prisma.io/docs/guides/upgrade-prisma-orm/postgresql). > [!NOTE] > Using Prisma ORM 7? > > Prisma ORM 8 is the current release, as a release candidate. Prisma ORM 7 remains fully supported; its docs live at [/orm/v7](https://www.prisma.io/docs/orm/v7) and its setup paths at [/v7/getting-started](https://www.prisma.io/docs/v7/getting-started). > > For what release candidate means, when the final release is expected, and how to stay on version 7, see [Release status](https://www.prisma.io/docs/orm/release-status). For the Prisma ORM 8 name of every Prisma ORM 7 API, see [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7). ## Prerequisites [#prerequisites] * A project directory with a `package.json`, on Node.js 22.18 or newer. * A way to run a TypeScript file. This page uses `tsx`. If your project does not have it, run `npm install --save-dev tsx typescript`. * An empty PostgreSQL database, version 15 or newer. Step 2 shows how to get one if you have none. ## 1. Add Prisma ORM to the project [#1-add-prisma-orm-to-the-project] The `orm init` command below changes your `tsconfig.json` and your `package.json`. In `tsconfig.json`, it sets `module` to `preserve` and `moduleResolution` to `bundler`. If your `package.json` has no `"type"` field, it adds `"type": "module"`. If it has `"type": "commonjs"`, the command keeps it and prints a warning. If your app runs as CommonJS, for example because it loads files with `require` or because `tsc` compiles it to `require` calls, follow [In a CommonJS project](https://www.prisma.io/docs/cli/orm-init#in-a-commonjs-project) before you start your app again. `tsx` runs the scripts on this page in both kinds of app, so you can finish this page first. From the root of your project, run: #### bun ```bash bunx prisma@latest orm init --yes --target postgres --authoring psl --write-env ``` #### pnpm ```bash pnpm dlx prisma@latest orm init --yes --target postgres --authoring psl --write-env ``` #### yarn ```bash yarn dlx prisma@latest orm init --yes --target postgres --authoring psl --write-env ``` #### npm ```bash npx prisma@latest orm init --yes --target postgres --authoring psl --write-env ``` `prisma@latest` runs Prisma ORM 8, and `--target postgres` picks PostgreSQL. `--authoring psl` picks PSL, the Prisma Schema Language, which is the `.prisma` file format you know from Prisma ORM 7. `--write-env` writes a `.env` file, unless you already have one. `--yes` accepts the default answer to every question, so the command asks nothing. The command installs the packages, writes the files, and ends with the summary below. In `package.json`, it adds the packages with their current version numbers, and a `contract:emit` script that runs `prisma contract emit`. If your project already has a `tsconfig.json` or a `.gitignore`, the command edits that file and keeps the rest of it. ```text no-copy │ target: postgres │ authoring: psl │ schema: src/prisma/contract.prisma written ├─ src/prisma/contract.prisma ├─ prisma.config.ts ├─ src/prisma/db.ts ├─ prisma-8.md ├─ .env.example ├─ .env ├─ tsconfig.json ├─ .gitignore ├─ .gitattributes └─ package.json installed ├─ @prisma/orm-postgres ├─ dotenv ├─ prisma@latest (dev) ├─ @types/node (dev) └─ @prisma/cli-engine@0.6.2 (dev) ✔ Done. Open prisma-8.md to get started. ``` You work with three of these files: * `src/prisma/contract.prisma` holds your models. It is what `schema.prisma` was in Prisma ORM 7, and Prisma ORM 8 calls it the contract. The summary lists it as `schema`. * `prisma.config.ts` tells the `prisma` commands where the contract is and which database to connect to. * `src/prisma/db.ts` is the file your app imports to run queries. You do not need `prisma-8.md` for this page. It is a short reference for writing queries. `.gitattributes` marks the files that Prisma ORM generates, so that GitHub collapses them in pull request diffs. `orm init` wrote `src/prisma/db.ts`, and you do not need to change it: ```typescript title="src/prisma/db.ts" import 'dotenv/config'; import postgres from '@prisma/orm-postgres/runtime'; import type { Contract } from './contract.d'; import contractJson from './contract.json' with { type: 'json' }; export const db = postgres({ contractJson, url: process.env['DATABASE_URL']!, }); ``` The first line loads `.env`, so every file that imports `db` reads `DATABASE_URL` from there. The two `contract` files it imports are written by `contract emit` in step 4. From now on, every `prisma` command ends with the line `Prisma agent skills are out of date`. You can ignore it, because it does not change what the command does. Agent skills are instruction files that AI coding tools read, and the line appears because your project has none yet. To add them and stop the line, run [`npx prisma@latest init`](https://www.prisma.io/docs/cli/init). In Prisma ORM 8, `init` adds the skills and a `postinstall` script that keeps them up to date, and it leaves your contract and your `.env` alone. `orm init` is the command that sets up Prisma ORM. ## 2. Set the connection string [#2-set-the-connection-string] If you had no `.env`, `orm init` wrote one with a placeholder, `DATABASE_URL="postgresql://user:password@localhost:5432/mydb"`. Open `.env` and set `DATABASE_URL` to the connection string of your database: ```bash title=".env" DATABASE_URL="postgresql://username:password@host:5432/database" ``` If you have no database at all, [`npx create-db@latest`](https://www.prisma.io/docs/postgres/npx-create-db) creates a temporary Prisma Postgres database and prints its connection string. `orm init` added `.env` to `.gitignore`, so the password stays out of version control. ## 3. Write one model [#3-write-one-model] `orm init` wrote a starter contract with a `User` and a `Post` model. Replace the contents of `src/prisma/contract.prisma` with one model: ```prisma title="src/prisma/contract.prisma" // use prisma-8 model User { id Int @id @default(autoincrement()) email String @unique name String? } ``` Keep the first line, because `contract emit` reads only `.prisma` files that start with it. The file has no `datasource` or `generator` block. The connection string comes from `.env`, and `contract emit` in the next step takes the place of the generator. [Data modeling](https://www.prisma.io/docs/orm/data-modeling) covers field types and relations. ## 4. Generate the files your code imports [#4-generate-the-files-your-code-imports] Run `contract emit` after every change to the contract. It takes the place of `prisma generate`. From here on, commands start with `npx prisma`, without `@latest`. That runs the version of Prisma ORM that `orm init` installed in your project: #### bun ```bash bunx prisma contract emit ``` #### pnpm ```bash pnpm prisma contract emit ``` #### yarn ```bash yarn prisma contract emit ``` #### npm ```bash npx prisma contract emit ``` ```text no-copy ✔ Resolving contract source... ✔ Emitting contract... │ contract: src/prisma/contract.json │ types: src/prisma/contract.d.ts ✔ Emitted contract.json and contract.d.ts ``` The command writes `contract.json` and `contract.d.ts` next to the contract. Commit both files, because `db.ts` imports them. ## 5. Create the table [#5-create-the-table] #### bun ```bash bunx prisma db init ``` #### pnpm ```bash pnpm prisma db init ``` #### yarn ```bash yarn prisma db init ``` #### npm ```bash npx prisma db init ``` ```text no-copy ✔ Introspecting database schema ✔ Planning migration ✔ Initialising database across spaces │ contract: src/prisma/contract.json │ database: postgres://****@127.0.0.1:54329/app1 ✔ Applied 2 operation(s) across 1 contract space App space ├─ Create table "User" ├─ Add unique constraint on "User" (email) └─ marker b5ae4e66fad1f0b7dd5590568f75a12a6f4576e9f367a787a69a4e729abac1fb ✔ Advanced ref "db" → b5ae4e66fad1f0b7dd5590568f75a12a6f4576e9f367a787a69a4e729abac1fb ``` `db init` creates the tables your contract declares. The output names two more things it wrote: * The `marker` is a record in the database. It holds the hash of your contract, which is the long text in the output, so that later commands can tell which version of the contract the database has. * The `db` ref is the file `migrations/app/refs/db.json` in your project. It holds the same hash. The line `Advanced ref "db"` means that the command wrote this file. `migration plan` in step 7 reads it to find out which contract your development database has. You can ignore the word `space` in the output, because all your migrations are in `migrations/app/`. Commit the `migrations/` directory together with your code, because `migration plan` reads it on every later change. If the command fails with `DRIVER.CONNECTION_FAILED`, the value of `DATABASE_URL` in `.env` is wrong or the database is not reachable. ## 6. Write and read a row [#6-write-and-read-a-row] Create `script.ts` in the root of your project: ```typescript title="script.ts" import { db } from "./src/prisma/db"; async function main() { const created = await db.orm.public.User.create({ email: "alice@example.com", name: "Alice", }); console.log("Created:", created); const users = await db.orm.public.User.all(); console.log("All users:", users); await db.close(); } main().catch((error) => { console.error(error); process.exit(1); }); ``` `db.orm` queries your models, the way Prisma Client did in Prisma ORM 7. You reach this model as `db.orm.public.User`, where `public` is the name of the PostgreSQL schema that holds your tables. `await db.close()` closes the database connections, and without it the script keeps running after the last query. `create` takes the fields directly, with no `data` wrapper, and `.all()` does what `findMany()` did. Run it: #### bun ```bash bunx tsx script.ts ``` #### pnpm ```bash pnpm dlx tsx script.ts ``` #### yarn ```bash yarn dlx tsx script.ts ``` #### npm ```bash npx tsx script.ts ``` ```text no-copy Created: { email: 'alice@example.com', id: 1, name: 'Alice' } All users: [ { email: 'alice@example.com', id: 1, name: 'Alice' } ] ``` In your app, import `db` from `src/prisma/db.ts` the same way. [Reading data](https://www.prisma.io/docs/orm/fundamentals/reading-data) and [Writing data](https://www.prisma.io/docs/orm/fundamentals/writing-data) show the other queries. ## 7. Change the model and apply the change [#7-change-the-model-and-apply-the-change] Add a field to the model: ```prisma title="src/prisma/contract.prisma" // use prisma-8 model User { id Int @id @default(autoincrement()) email String @unique name String? phone String? // [!code ++] } ``` Generate the files again, then plan a migration. `migration plan` compares the new contract with the last one you applied to your development database, and writes the difference into a new directory under `migrations/app/`. `--name` sets the end of the directory's name, after the date and time. #### bun ```bash bunx prisma contract emit bunx prisma migration plan --name add_user_phone ``` #### pnpm ```bash pnpm prisma contract emit pnpm prisma migration plan --name add_user_phone ``` #### yarn ```bash yarn prisma contract emit yarn prisma migration plan --name add_user_phone ``` #### npm ```bash npx prisma contract emit npx prisma migration plan --name add_user_phone ``` ```text no-copy │ contract: src/prisma/contract.json │ migrations: migrations/app │ name: add_user_phone ✔ Planned baseline (3 operation(s)) + 1 operation(s) migrations/app/20260929T2120_baseline ├─ Create schema "public" ├─ Create table "User" └─ Add unique constraint on "User" (email) migrations/app/20260929T2121_add_user_phone └─ Add column "phone" to "User" from: b5ae4e66fad1f0b7dd5590568f75a12a6f4576e9f367a787a69a4e729abac1fb to: 300832575ace8feebb3d3442d1bca52150c46628de3e4c6c32a61cb0ab21100f baseline: migrations/app/20260929T2120_baseline app space: migrations/app/20260929T2121_add_user_phone ``` The output continues with a preview of the SQL. The first plan in a project writes two directories. The baseline holds the steps that create the table, which `db init` already ran on your development database. The second directory is your change. Apply the migration: #### bun ```bash bunx prisma db migrate --advance-ref db ``` #### pnpm ```bash pnpm prisma db migrate --advance-ref db ``` #### yarn ```bash yarn prisma db migrate --advance-ref db ``` #### npm ```bash npx prisma db migrate --advance-ref db ``` ```text no-copy ✔ Running migration plan across spaces │ migrations: migrations │ database: postgres://****@127.0.0.1:54329/app1 ✔ Applied 1 migration(s) (1 operation(s)) across 1 contract space(s) App space ├─ Add column "phone" to "User" └─ marker 300832575ace8feebb3d3442d1bca52150c46628de3e4c6c32a61cb0ab21100f ✔ Advanced ref "db" → 300832575ace8feebb3d3442d1bca52150c46628de3e4c6c32a61cb0ab21100f ``` `db migrate` runs only the migrations that the database does not have yet, so here it runs only your change. `--advance-ref db` writes the new hash to the `db` ref, so that the next `migration plan` contains only your next change. Pass it every time you apply a migration to your development database. Commit the `migrations/` directory again. To apply the migrations to any other database, such as production, pass its connection string. Leave out `--advance-ref`, because the `db` ref describes your development database: #### bun ```bash bunx prisma db migrate --db "$PRODUCTION_DATABASE_URL" ``` #### pnpm ```bash pnpm prisma db migrate --db "$PRODUCTION_DATABASE_URL" ``` #### yarn ```bash yarn prisma db migrate --db "$PRODUCTION_DATABASE_URL" ``` #### npm ```bash npx prisma db migrate --db "$PRODUCTION_DATABASE_URL" ``` `db migrate` runs the migrations that this database does not have yet. An empty database has no marker, so there `db migrate` runs the baseline and then your change. Every later change follows the same four steps, which take the place of `prisma migrate dev`: edit `src/prisma/contract.prisma`, run `npx prisma contract emit`, run `npx prisma migration plan --name `, and run `npx prisma db migrate --advance-ref db`. ## Next steps [#next-steps] * [Data modeling](https://www.prisma.io/docs/orm/data-modeling) for relations, more field types, and indexes. * [Generating a migration](https://www.prisma.io/docs/orm/migrations/generating-a-migration) for what a migration directory contains and how to edit it. * [`db update`](https://www.prisma.io/docs/cli/db-update) to apply a contract change to a development database without writing migration files. * [Coming from Prisma ORM 7](https://www.prisma.io/docs/orm/coming-from-prisma-orm-7) for the Prisma ORM 8 name of each Prisma ORM 7 call. ## Related pages - [`Add Prisma ORM and MongoDB to an existing app`](https://www.prisma.io/docs/prisma-orm/quickstart/existing-app/mongodb): Add Prisma ORM to an app you already have, create the collections in an empty MongoDB database, run a first query, and apply a first migration.