'How do I run Prisma migrations in a Dockerized GraphQL + Postgres setup?

I'm new to using Prisma as well as Dockerizing my setup. I would like to specify my data model using Prisma, have Postgres as my database and use that in a GraphQL API (my current API uses apollo-server-express) that also deals with authentication and roles etc.

What I have now is a simple docker-compose.yml and a Dockerfile of my GraphQL API:

docker-compose.yml

services:
  api:
    build: ./api
    env_file:
      - .env
    volumes:
      - ./api:/usr/src/app
    ports:
      - ${API_PORT}:${API_PORT}
    command: npm start

Dockerfile

# Latest LTS version
FROM node:14

# Set default values for environment variables
ENV API_PORT=3001

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
COPY package*.json ./
RUN npm install

# Bundle app source
COPY . .

# Bind port
EXPOSE ${API_PORT}

# Start server
CMD ["npm", "start"]

How would I go about using Prisma and Postgres in this setup, where the migrations happen in some containerized way, instead of me executing a Prisma command manually in the CLI?

Pointing out my misconceptions, hints or feedback is appreciated! Thank you



Solution 1:[1]

Late answer to my own question: Like @Athir suggested I now separated the two processes and created two docker-compose.yml files: one named docker-compose.migrate.yml that's responsible for running the migration and one named docker-compose.yml which is the main application.

My docker-compose.migrate.yml:

version: '3'
services:
  prisma-migrate:
    container_name: prisma-migrate
    build: ./api/prisma
    env_file:
      - .env
    environment:
      DB_HOST: <secret>
    depends_on:
      - db

  db:
    image: postgres:13
    container_name: db
    restart: always
    env_file:
      - .env
    environment:
      DB_PORT: 5432
    ports:
      - ${DB_PORT}:5432
    volumes:
      - ${POSTGRES_VOLUME_DIR}:/var/lib/postgresql/data

With the following Prisma Dockerfile:

FROM node:14

RUN echo $DATABASE_URL

WORKDIR /app

COPY ./package.json ./
COPY . ./prisma/

RUN chmod +x ./prisma/wait-for-postgres.sh

RUN npm install
RUN npx prisma generate

RUN apt update
RUN apt --assume-yes install postgresql-client

# Git will replace the LF line-endings with CRLF, causing issues while executing the wait-for-postgres shell script
# Install dos2unix and replace CRLF (\r\n) newlines with LF (\n)
RUN apt --assume-yes install dos2unix
RUN dos2unix ./prisma/wait-for-postgres.sh

CMD sh ./prisma/wait-for-postgres.sh ${DB_HOST} ${POSTGRES_USER} npx prisma migrate deploy && npx prisma db seed --preview-feature

EDIT: wait-for-postgres.sh:

#!/bin/sh
# wait-for-postgres.sh

set -e
  
host="$1"
user="$2"
shift
shift
cmd="$@"
  
until PGPASSWORD=$POSTGRES_PASSWORD psql -h "$host" -U "$user" -c '\q'; do
  >&2 echo "Postgres is unavailable - sleeping"
  sleep 1
done
  
>&2 echo "Postgres is up - executing command"

exec $cmd

EDIT: example .env file:

# ---- DB ----
DB_HOST=localhost
DB_PORT=5432
DB_SCHEMA=example

POSTGRES_DB=example
POSTGRES_USER=example
POSTGRES_VOLUME_DIR=/path/where/you/want/to/store
POSTGRES_PASSWORD=example

DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${DB_HOST}:${DB_PORT}/${POSTGRES_DB}?schema=${DB_SCHEMA}

Solution 2:[2]

You need to run the migration before you start your nextjs app. There are several ways you can do this. Some people do this as part of this CI/CD scripts. In your case of using docker compose, you can change the startup command to run a script that runs the migration before starting up your app.

First, create your bash script

npx prisma migrate deploy
npm start

then change your Dockerfile to run the script

CMD ["startup.sh"]

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Athir Nuaimi