The Ultimate Guide to Prisma ORM + PostgreSQL (2025 Edition)

Published: (December 22, 2025 at 07:01 AM EST)
3 min read
Source: Dev.to

Source: Dev.to

Project Initialization

Start by setting up your Node.js environment with TypeScript. We use tsx for modern, fast execution.

mkdir prisma-postgres-2025
cd prisma-postgres-2025
npm init -y
npm install typescript tsx @types/node --save-dev
npx tsc --init

Install Prisma and PostgreSQL Driver

In 2025, it is highly recommended to install the official PostgreSQL adapter for better performance in serverless and edge environments.

npm install prisma --save-dev
npm install @prisma/client @prisma/adapter-pg pg

Initialize Prisma

Run the following to generate your boilerplate. This creates the prisma/schema.prisma file and a .env file.

npx prisma init --datasource-provider postgresql

Configure Your Connection

Open your .env file. PostgreSQL connection strings follow this format:

# Format: postgresql://USER:PASSWORD@HOST:PORT/DATABASE?schema=public
DATABASE_URL="postgresql://postgres:mypassword@localhost:5432/mydb?schema=public"

Define Your Modern Schema

In prisma/schema.prisma, define your models. These act as the “proxy” to your database.

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
}

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  author    User    @relation(fields: [authorId], references: [id])
  authorId  Int
}

Apply Migrations

Use Prisma Migrate to push your schema to PostgreSQL. This creates the actual tables and generates your type‑safe client.

npx prisma migrate dev --name init

Instantiate the Client (Singleton Pattern)

To prevent “Too many connections” errors in PostgreSQL (especially during development with hot‑reloading), use this singleton pattern:

// db.ts
import { PrismaClient } from '@prisma/client'

const globalForPrisma = global as unknown as { prisma: PrismaClient }

export const prisma = globalForPrisma.prisma || new PrismaClient()

if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma

Performing CRUD Operations

Now you can write fully type‑safe queries. Prisma handles the PostgreSQL JOINs and relations automatically.

import { prisma } from './db'

async function run() {
  // Create a user and a post in one transaction
  const user = await prisma.user.create({
    data: {
      email: 'hello@dev.to',
      name: 'Dev Reader',
      posts: {
        create: { title: 'Learning Prisma in 2025' }
      }
    }
  })

  // Read: Fetch all users and include their posts
  const allUsers = await prisma.user.findMany({
    include: { posts: true }
  })

  console.log(JSON.stringify(allUsers, null, 2))
}

run()

What’s New for PostgreSQL in 2025?

  • Rust‑Free Engine: Prisma 6/7 moved to a TypeScript‑based engine, resulting in faster cold starts and smaller Docker images.
  • TypedSQL: Write raw SQL in .sql files and have Prisma generate TypeScript types for them, combining raw‑SQL power with ORM safety.
  • Prisma Studio: Run npx prisma studio to launch a visual dashboard for your PostgreSQL data—ideal for quick debugging without a separate DB manager.
  • Pro‑Tip: When using hosted PostgreSQL providers such as Supabase or Neon, use their “Connection Pooling” strings in your .env to handle high traffic efficiently.
Back to Blog

Related posts

Read more »

Week 11: Prisma!

Topics Covered✅ - Understanding what an ORM actually solves - Defining a database schema using Prisma - Generating type‑safe database clients - Performing CRUD...