I have a NestJS app using Mikro-ORM and PostgreSQL. I’m new to Dockerizing database migrations and Mikro-ORM in NestJS.
Locally, when I run:
npx mikro-orm migration:create npx mikro-orm migration:up npm run start:dev all entity tables are created and I can see them in the database.
But when I run the app in Docker Compose:
The app builds and starts without errors. Only the mikro_orm_migrations table exists in the database; none of my entity tables appear.
My current setup:
docker-compose.yml snippet:
services: postgres: image: postgres:15 environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: app_db ports: - '5432:5432' volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 3s timeout: 5s retries: 5 app: build: . container_name: app environment: DB_HOST: postgres DB_PORT: 5432 DB_USER: postgres DB_PASSWORD: postgres DB_NAME: app_db NODE_ENV: production ports: - '3000:3000' depends_on: postgres: condition: service_healthy command: sh -c " echo 'Waiting for DB...'; sleep 5; echo 'Running migrations...'; npx mikro-orm migration:create; npx mikro-orm migration:up --config dist/mikro-orm.config.js; echo 'Starting app...'; node dist/src/main.js" volumes: postgres_data: mikro-orm.config.ts at the root of project:
import { defineConfig } from '@mikro-orm/postgresql'; import { PostgreSqlDriver } from '@mikro-orm/postgresql'; export default defineConfig({ driver: PostgreSqlDriver, dbName: process.env.DB_NAME || 'app_db', user: process.env.DB_USER || 'postgres', password: process.env.DB_PASSWORD || 'postgres', host: process.env.DB_HOST || 'localhost', port: Number(process.env.DB_PORT) || 5432, debug: true, entities: ['./dist/**/*.entity.js'], entitiesTs: process.env.NODE_ENV === 'development' ? ['./src/**/*.entity.ts'] : undefined, migrations: { tableName: 'mikro_orm_migrations', path: './dist/src/database/migrations', pathTs: './src/database/migrations', }, }); and dockerfile:
FROM node:22-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM node:22-alpine WORKDIR /app COPY --from=builder /app/package*.json ./ COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/dist ./dist COPY --from=builder /app/mikro-orm.config.ts ./mikro-orm.config.ts ENV NODE_ENV=production CMD ["node", "dist/src/main.js"] Why do migrations work locally but in Docker Compose only the mikro_orm_migrations table is created and my entity tables are missing?
And another question...
What is the best practice for running database migrations in Docker/production?
Should migrations be part of the Docker Compose startup or should they be handled by a separate CI/CD step before deploying the container?