apps/docs/content/docs/guides/deployment/docker.mdx
This guide walks you through setting up a Prisma ORM application within a Docker environment. You'll learn how to configure a Node.js project, integrate Prisma for database management, and orchestrate the application using Docker Compose. By the end, you'll have a fully functional Prisma application running in a Docker container.
See our system requirements for all minimum version requirements.
Before starting, ensure that no PostgreSQL services are running locally, and that the following ports are free to avoid conflicts: 5432 (PostgreSQL), 3000 (application server) or 5555 (Prisma Studio server).
To stop existing PostgreSQL services, use:
sudo systemctl stop postgresql # Linux
brew services stop postgresql # macOS
net stop postgresql # Windows (Run as Administrator)
To stop all running Docker containers and free up ports:
docker ps -q | xargs docker stop
Let's start by creating a simple Node.js application with Prisma ORM and Express.js.
First, create a new project directory and initialize a Node.js project:
mkdir docker-test
cd docker-test
npm init -y
This will generate a package.json file:
{
"name": "docker-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {},
"keywords": [],
"author": "",
"license": "ISC"
}
Next, install the Prisma CLI as a development dependency and Express.js for the server:
npm install prisma @types/pg --save-dev
npm install @prisma/client @prisma/adapter-pg pg dotenv express
:::info
If you are using a different database provider (MySQL, SQL Server, SQLite), install the corresponding driver adapter package instead of @prisma/adapter-pg. For more information, see Database drivers.
:::
Now, initialize Prisma to generate the necessary files:
npx prisma init --output ../generated/prisma
This creates:
prisma folder containing schema.prisma, where you will define your database schema..env file in the project root, which stores environment variables.Add a User model to the schema.prisma file located in the prisma/schema.prisma folder:
datasource db {
provider = "postgresql"
}
generator client {
provider = "prisma-client"
output = "../generated/prisma_client" // [!code ++]
}
model User { // [!code ++]
id Int @id @default(autoincrement()) // [!code ++]
createdAt DateTime @default(now()) // [!code ++]
email String @unique // [!code ++]
name String? // [!code ++]
} // [!code ++]
:::note
In the schema.prisma file, we specify a custom output path where Prisma will generate its types. This ensures Prisma's types are resolved correctly across different package managers and can be accessed by application consistently inside the container without any permission issues. In this guide, the types will be generated in the ./generated/prisma_client directory.
:::
Now, create a prisma.config.ts file in the root of your project:
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"),
},
});
:::note
You'll need to install the dotenv package to load environment variables:
npm install dotenv
:::
With the Prisma schema in place, let's create an Express.js server to interact with the database. Start by creating an index.js file:
touch index.js
Add the following code to set up a basic Express server:
const express = require("express"); // [!code ++]
const { PrismaClient } = require("./generated/prisma_client/client"); // [!code ++]
const { PrismaPg } = require("@prisma/adapter-pg"); // [!code ++]
// [!code ++]
const adapter = new PrismaPg({
// [!code ++]
connectionString: process.env.DATABASE_URL, // [!code ++]
}); // [!code ++]
// [!code ++]
const app = express(); // [!code ++]
const prisma = new PrismaClient({
// [!code ++]
adapter, // [!code ++]
}); // [!code ++]
app.use(express.json()); // [!code ++]
// [!code ++]
// Get all users // [!code ++]
app.get("/", async (req, res) => {
// [!code ++]
const userCount = await prisma.user.count(); // [!code ++]
res.json(
// [!code ++]
userCount == 0 // [!code ++]
? "No users have been added yet." // [!code ++]
: "Some users have been added to the database.", // [!code ++]
); // [!code ++]
}); // [!code ++]
// [!code ++]
const PORT = 3000; // [!code ++]
// [!code ++]
app.listen(PORT, () => {
// [!code ++]
console.log(`Server is running on http://localhost:${PORT}`); // [!code ++]
}); // [!code ++]
Update the package.json scripts to include commands for running the server and deploying migrations:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1", // [!code --]
"dev": "node index.js", // [!code ++]
"db:deploy": "npx prisma migrate deploy && npx prisma generate" // [!code ++]
}
Now that the application is set up, let's move on to configuring a PostgreSQL database using Docker Compose.
To perform database migrations, we'll create a standalone PostgreSQL database using Docker Compose.
Create a docker-compose.postgres.yml file in the root directory:
version: '3.7' // [!code ++]
// [!code ++]
services: // [!code ++]
postgres: // [!code ++]
image: postgres:15 // [!code ++]
restart: always // [!code ++]
environment: // [!code ++]
- POSTGRES_DB=postgres // [!code ++]
- POSTGRES_USER=postgres // [!code ++]
- POSTGRES_PASSWORD=prisma // [!code ++]
ports: // [!code ++]
- "5432:5432" // [!code ++]
networks: // [!code ++]
- prisma-network // [!code ++]
healthcheck: // [!code ++]
test: ["CMD-SHELL", "pg_isready -U prisma -d postgres"] // [!code ++]
interval: 5s // [!code ++]
timeout: 2s // [!code ++]
retries: 20 // [!code ++]
volumes: // [!code ++]
- postgres_data:/var/lib/postgresql/data // [!code ++]
command: postgres -c listen_addresses='*' // [!code ++]
logging: // [!code ++]
options: // [!code ++]
max-size: "10m" // [!code ++]
max-file: "3" // [!code ++]
// [!code ++]
networks: // [!code ++]
prisma-network: // [!code ++]
// [!code ++]
volumes: // [!code ++]
postgres_data: // [!code ++]
Run the following command to start the database:
docker compose -f docker-compose.postgres.yml up -d
With the database running, update the .env file with the following database connection url:
DATABASE_URL="postgresql://postgres:prisma@localhost:5432/postgres?schema=public" // [!code highlight]
Run the migration to create the database schema:
npx prisma migrate dev --name init
Then generate Prisma Client:
npx prisma generate
This should generate a migrations folder in the prisma folder and the Prisma Client in the generated/prisma_client directory.
Start the server and verify it works:
npm run dev
Visit http://localhost:3000 to see the message:
No users have been added yet.
Stop the local server.
Once testing is complete, remove the standalone PostgreSQL container:
docker compose -f docker-compose.postgres.yml down --remove-orphans
This command will:
Now that we've tested the application locally, let's containerize it using Docker.
We'll now containerize the application using Docker, ensuring it can run in any environment.
To do that create a Dockerfile in project root:
touch Dockerfile
For the next step, you'll need to choose between two options for the base image: node:alpine (lightweight) or node:slim (stable). Both options are fully supported by Prisma ORM, but may have to be configured differently.
node:alpine) as a base imageThe node:alpine image is based on Alpine Linux, a lightweight Linux distribution that uses the musl C standard library. It's perfect if you want to keep your container small and efficient. Prisma supports Alpine on amd64 out of the box, and supports it on arm64 since [email protected].
Add the following content to the Dockerfile:
FROM node:lts-alpine3.17
WORKDIR /usr/src/app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
CMD ["sh", "-c", "npm run db:deploy && npm run dev"]
:::note
When running on Linux Alpine, Prisma downloads engines that are compiled for the musl C standard library. Please don't install glibc on Alpine (e.g., via the libc6-compat package), as that would prevent Prisma from running successfully.
:::
Related Docker images:
node:lts-alpinenode:16-alpinenode:14-alpinenode:slim) as a base imageThe node:slim image is based on Linux Debian, a stable and widely supported distribution that uses the glibc C standard library. It is mostly supported out of the box on amd64 and arm64, making it a good choice if you're running into compatibility issues with Alpine or need a more production-ready environment. However, some older versions of this image may come without libssl installed, so it's sometimes necessary to install it manually.
Add the following content to the Dockerfile:
FROM node:slim
RUN apt-get update -y \
&& apt-get install -y openssl
WORKDIR /usr/src/app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
CMD ["sh", "-c", "npm run db:deploy && npm run dev"]
Related Docker images:
node:lts-slimnode:bullseye-slimnode:buster-slimnode:stretch-slimNow that the Dockerfile is ready, we'll use Docker Compose to manage both the app and the database together. This makes it easy to start, stop, and manage the entire setup.
Create a docker-compose.yml file in your project folder:
touch docker-compose.yml
Add the following configuration to the file:
version: '3.7' // [!code ++]
// [!code ++]
services: // [!code ++]
postgres_db: // [!code ++]
image: postgres:15 // [!code ++]
hostname: postgres_db // [!code ++]
container_name: postgres_db // [!code ++]
restart: always // [!code ++]
environment: // [!code ++]
POSTGRES_DB: postgres // [!code ++]
POSTGRES_USER: postgres // [!code ++]
POSTGRES_PASSWORD: prisma // [!code ++]
ports: // [!code ++]
- '5432:5432' // [!code ++]
networks: // [!code ++]
- prisma-network // [!code ++]
healthcheck: // [!code ++]
test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"] // [!code ++]
interval: 5s // [!code ++]
timeout: 2s // [!code ++]
retries: 20 // [!code ++]
// [!code ++]
server: // [!code ++]
build: // [!code ++]
context: . // [!code ++]
dockerfile: Dockerfile // [!code ++]
ports: // [!code ++]
- '3000:3000' // [!code ++]
stdin_open: true // [!code ++]
tty: true # Keeps the container running for debugging // [!code ++]
depends_on: // [!code ++]
postgres_db: // [!code ++]
condition: service_healthy // [!code ++]
env_file: // [!code ++]
- .env.prod // [!code ++]
networks: // [!code ++]
- prisma-network // [!code ++]
networks: // [!code ++]
prisma-network: // [!code ++]
name: prisma-network // [!code ++]
Before running the app, we need to configure the environment variables. Create a .env.prod file:
touch .env.prod
Add the following database connection url to the .env.prod file:
DATABASE_URL="postgresql://postgres:prisma@postgres_db:5432/postgres?schema=public" // [!code highlight]
With everything set up, it's time to build and run the app using Docker Compose. Run the following command:
docker compose -f docker-compose.yml up --build -d
Visit http://localhost:3000 to see your app running with the message:
No users have been added yet.
Prisma Studio offers a graphical user interface (GUI) that allows you to view and manage your database directly in the browser. It's a great tool for debugging and managing your data during development.
To add Prisma Studio to your Docker setup, update the docker-compose.yml file:
version: '3.7'
services:
postgres_db:
image: postgres:15
hostname: postgres_db
container_name: postgres_db
restart: always
environment:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: prisma
ports:
- '5432:5432'
networks:
- prisma-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"]
interval: 5s
timeout: 2s
retries: 20
server:
build:
context: .
dockerfile: Dockerfile
ports:
- '3000:3000'
stdin_open: true
tty: true # Keeps the container running for debugging
depends_on:
postgres_db:
condition: service_healthy
env_file:
- .env.prod
networks:
- prisma-network
prisma-studio: // [!code ++]
image: node:lts-alpine3.17 // [!code ++]
working_dir: /usr/src/app // [!code ++]
volumes: // [!code ++]
- .:/usr/src/app // [!code ++]
command: npx prisma studio --port 5555 --browser none // [!code ++]
ports: // [!code ++]
- "5555:5555" // [!code ++]
env_file: // [!code ++]
- .env.prod // [!code ++]
networks: // [!code ++]
- prisma-network // [!code ++]
depends_on: // [!code ++]
postgres_db: // [!code ++]
condition: service_healthy // [!code ++]
server: // [!code ++]
condition: service_started // [!code ++]
networks:
prisma-network:
name: prisma-network
This will start Prisma Studio at http://localhost:5555 alongside the main app at http://localhost:3000. You can use Prisma Studio to manage your database with a GUI.
Run the following command to start everything:
docker compose -f docker-compose.yml up --build -d
By following this guide, you've successfully containerized your Prisma app and database using Docker Compose.