Back to guides

Run Own Auth with Docker and Postgres


Own Auth runs inside the application container and stores authentication records in Postgres by default. The Compose setup below starts Postgres, applies the Own Auth migrations in a one-off container, and starts the backend only after the migration completes.

Build the application image

This Dockerfile installs dependencies, builds the TypeScript backend, removes development packages, and copies the compiled application into the runtime image.

Dockerfile
FROM node:22-slim AS build
WORKDIR /app

COPY package*.json ./
RUN npm ci

COPY . .
RUN npm run build
RUN npm prune --omit=dev

FROM node:22-slim
WORKDIR /app
ENV NODE_ENV=production

COPY --from=build /app/package*.json ./
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist

CMD ["node", "dist/server.js"]

Run migrations before the application

compose.yaml
services:
  db:
    image: postgres:17
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: app
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d app"]
      interval: 5s
      timeout: 5s
      retries: 10
    volumes:
      - postgres-data:/var/lib/postgresql/data

  migrate:
    build: .
    command: ["npx", "own-auth", "migrate"]
    environment:
      DATABASE_URL: postgres://app:${POSTGRES_PASSWORD}@db:5432/app
    depends_on:
      db:
        condition: service_healthy

  app:
    build: .
    environment:
      DATABASE_URL: postgres://app:${POSTGRES_PASSWORD}@db:5432/app
      OWN_AUTH_TOKEN_PEPPER: ${OWN_AUTH_TOKEN_PEPPER}
    depends_on:
      migrate:
        condition: service_completed_successfully
    ports:
      - "3000:3000"

volumes:
  postgres-data:

The Postgres health check gates the migration container. The application starts only after npx own-auth migrate exits successfully. The postgres-data volume keeps Own Auth tables when the database container is replaced.

Start the stack

Terminal
docker compose up --build