A Complete Guide to Using Prisma 7 with Docker and Docker Compose in NestJS

Published: (February 1, 2026 at 10:56 AM EST)
6 min read
Source: Dev.to

Source: Dev.to

If you have ever tried running Prisma inside Docker and ended up stuck with connection errors that made absolutely no sense, this article is for you.

Modern backend applications often rely on ORMs such as Prisma, TypeORM, or Mongoose for database access, alongside Docker for consistent development environments. While each tool works great on its own, combining Prisma with Docker—especially with a containerised database—can be surprisingly tricky.

TL;DR – I spent almost two days debugging why Prisma could not connect to a PostgreSQL database running in Docker. This guide walks you through a step‑by‑step setup, common pitfalls, and best practices for running migrations in a containerised environment.

📋 Prerequisites

  • Basic knowledge of NestJS
  • Basic understanding of Docker and Docker‑Compose
  • Docker Desktop installed and running
  • A code editor (e.g., VS Code)

What is Prisma?

Prisma is an open‑source ORM (Object‑Relational Mapper) that simplifies database operations by mapping tables to JavaScript/TypeScript objects. Instead of writing raw SQL, you interact with your database using type‑safe APIs.

// Raw SQL
SELECT * FROM users WHERE email = 'john@example.com';

// Prisma
const user = await prisma.user.findUnique({
  where: { email: 'john@example.com' },
});

Benefits

  • Improves readability
  • Reduces runtime errors
  • Provides excellent TypeScript support

Prisma 7 Highlights (relevant for Docker)

FeatureWhy it matters for Docker
Rust‑free client engineFewer binary‑compatibility issues, especially with Alpine images
Fewer type definitionsFaster TypeScript compilation, better editor performance
Modern JavaScript supportAligns with newer Node.js runtimes
Cleaner developer experienceSimplified configuration, fewer edge‑case errors

Minimum requirements

  • Node.js 20.19.0+
  • TypeScript 5.4.0+

Why Docker?

Docker packages your application and its dependencies into containers, guaranteeing that it runs the same everywhere.

Benefits

  • Consistent environments across teams
  • Faster onboarding
  • Easier deployment & scaling
  • Fewer “works on my machine” issues

NestJS Overview

NestJS is a framework for building efficient, scalable Node.js server‑side applications. It’s built with TypeScript and supports:

  • Object‑Oriented Programming (OOP)
  • Functional Programming (FP)
  • Functional Reactive Programming (FRP)

Under the hood it uses Express by default (or Fastify if you prefer).

Install the NestJS CLI globally

npm install -g @nestjs/cli

Create a new project

nest new backend

Scaffolds:

  • TypeScript configuration
  • Project structure
  • Core dependencies

Generate controllers/services as needed:

nest g controller users
nest g service users

Adding Prisma to the NestJS Project

1️⃣ Install Prisma packages

# Development dependencies
npm install prisma @types/pg --save-dev

# Runtime dependencies
npm install @prisma/client @prisma/adapter-pg pg dotenv

2️⃣ Initialise Prisma

npx prisma init

Creates a prisma/ directory with schema.prisma and a .env file.

3️⃣ Configure the Prisma client generator (Prisma 7)

Add to prisma/schema.prisma (or a separate prisma.config.ts):

generator client {
  provider     = "prisma-client"
  output       = "../src/generated/prisma"
  moduleFormat = "cjs"
}

4️⃣ Create a NestJS Prisma module & service

nest g module prisma
nest g service prisma

src/prisma/prisma.service.ts

import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import { PrismaPg } from '@prisma/adapter-pg';
import { PrismaClient } from 'src/generated/prisma/client';

@Injectable()
export class PrismaService
  extends PrismaClient
  implements OnModuleInit, OnModuleDestroy
{
  constructor() {
    const adapter = new PrismaPg({
      connectionString: process.env.DATABASE_URL,
    });
    super({ adapter, log: ['query', 'info', 'warn', 'error'] });
  }

  async onModuleInit() {
    await this.$connect();
  }

  async onModuleDestroy() {
    await this.$disconnect();
  }
}

This service:

  • Creates the prisma/ directory and generates schema.prisma
  • Adds a .env file (if missing)
  • Generates a prisma.config.ts (new in Prisma 7)

Dockerising PostgreSQL (stand‑alone container)

Tip: Make sure Docker Desktop is running before proceeding.

1️⃣ Create docker-compose.yml in the project root

services:
  postgres:
    image: postgres:15
    restart: always
    environment:
      POSTGRES_DB: postgres
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: backend
    ports:
      - "5432:5432"
    networks:
      - prisma-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"]
      interval: 5s
      timeout: 2s
      retries: 20
    volumes:
      - postgres_data:/var/lib/postgresql/data
    logging:
      options:
        max-size: "10m"
        max-file: "3"

networks:
  prisma-network:

volumes:
  postgres_data:

2️⃣ Bring the DB up

docker compose up -d

3️⃣ Set the connection string

Add to .env (or replace existing DATABASE_URL):

DATABASE_URL="postgresql://postgres:backend@localhost:5432/postgres?schema=public"

Note: If localhost doesn’t work on your machine, use 127.0.0.1.

4️⃣ Run the first migration & generate the client

npx prisma migrate dev --name initial-migration
npx prisma generate

5️⃣ Start the NestJS app & open Prisma Studio

npm run start   # or npm run dev
npx prisma studio

You should now see a working NestJS API backed by Prisma and a Dockerised PostgreSQL instance.

Building a Docker Image for the NestJS Server

Create a Dockerfile in the project root. Both Alpine‑based and Slim‑based images are supported by Prisma 7.

Example Dockerfile (Alpine)

# Use the LTS Alpine image (lightweight)
FROM node:lts-alpine

# Set working directory
WORKDIR /usr/src/app

# Install production dependencies
COPY package.json package-lock.json ./
RUN npm ci --omit=dev

# Copy source code
COPY . .

# Run DB migrations then start the server
CMD ["sh", "-c", "npm run db:deploy && npm run dev"]

Alternative base images

  • node:lts-slim – slightly larger but more stable
  • node:lts – full Debian‑based image

Adding the Server to docker‑compose.yml

Extend the existing file with a server service that builds the Dockerfile.

services:
  postgres:
    # ... (same as before)

  server:
    build:
      context: .
      dockerfile: Dockerfile
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      DATABASE_URL: "postgresql://postgres:backend@postgres:5432/postgres?schema=public"
    ports:
      - "3000:3000"
    networks:
      - prisma-network
    command: ["sh", "-c", "npm run db:deploy && npm run start:prod"]

Key points

  • depends_on ensures the DB is healthy before the NestJS app starts.
  • DATABASE_URL points to the service name (postgres) inside the Docker network, not localhost.

Bring everything up

docker compose up -d

Access the NestJS API at http://localhost:3000 and Prisma Studio at http://localhost:5555 (if exposed).

Common Pitfalls & How to Avoid Them

SymptomLikely CauseFix
PrismaClientInitializationError: Unable to connect to databaseWrong host (localhost instead of service name)Use postgres (service name) in DATABASE_URL when running inside Docker
binary not found or unsupported platformUsing an Alpine image with the old Rust‑based engineUpgrade to Prisma 7 (Rust‑free) or switch to a non‑Alpine base
Migrations keep failingDB not ready when migration runsUse Docker healthchecks + depends_on with condition: service_healthy
TypeScript compilation slows downToo many type definitions (pre‑Prisma 7)Upgrade to Prisma 7 – fewer definitions, faster builds

Recap

  1. Set up NestJS and add Prisma.
  2. Create a Dockerised PostgreSQL service with healthchecks.
  3. Configure the Prisma client to use the Docker network host.
  4. Run migrations (npx prisma migrate dev) before starting the server.
  5. Dockerise the NestJS app with a lightweight Node image.
  6. Compose everything with docker‑compose.yml and bring it up.

You now have a reproducible, container‑first development environment where Prisma 7, Docker, and NestJS work together seamlessly. Happy coding! 🚀

Docker Compose Setup

services:
  app:
    context: .
    dockerfile: Dockerfile
    ports:
      - "3000:3000"
    stdin_open: true
    tty: true
    depends_on:
      postgres_db:
        condition: service_healthy
    env_file:
      - .env.prod
    networks:
      - prisma-network

networks:
  prisma-network:
    name: prisma-network

Environment Files

Create two separate files for each environment:

  • .env.dev
  • .env.prod

Both should contain the database connection string:

DATABASE_URL="postgresql://postgres:prisma@postgres_db:5432/postgres?schema=public"

Running the Containers

  • Detached mode (reduced logs)

    docker compose up --build -d
  • Full logs

    docker compose up --build

Tip: Adding the -d flag runs the containers in detached mode, which suppresses most of the log output.

Common Pitfalls & Fixes

IssueFix
Inside Docker, localhost refers to the container itself.Use the Docker service name instead: postgres_db:5432.
Containers may start before PostgreSQL is ready.Add a wait script or use Docker health checks before running migrations.
Prisma Client isn’t generated inside the container, causing crashes.Run npx prisma generate during the Docker build step.
Older Prisma versions have trouble with Alpine images.Upgrade to Prisma 7 – its Rust‑free client engine greatly reduces this problem.

Why Use Prisma 7 with Docker & Docker‑Compose?

  • Reliable migrations – health checks ensure the DB is ready before applying them.
  • Environment‑agnostic – separate .env files prevent bugs that only appear in one environment.
  • Scalable workflow – the same configuration works from local development to production.

If this guide helped you, feel free to like, comment, or share.
Explore the full example repository:

🔗 https://github.com/idongesit98/DockerProject

Back to Blog

Related posts

Read more »