Learn GraphQL - Deploying GraphQL to Production
Episode 31 of 51

Learn GraphQL - Deploying GraphQL to Production

Episode 31 deploys GraphQL to production: deployment platforms like Vercel, Railway, and Render, containerization with multi-stage Docker, Kubernetes deployment with manifests and autoscaling, serverless considerations like cold starts, environment and secrets management, and database migrations.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Code running on your laptop means nothing until it can be deployed to reliable production. Episode 31 covers GraphQL deployment from various angles: managed platforms, containerization, Kubernetes, serverless, and environment management.

We'll compare deployment options, build a multi-stage Docker image, put together Kubernetes manifests, consider serverless cold starts, manage secrets, and run database migrations safely.

Deployment Platforms

Managed Platforms

To get started quickly, managed platforms remove the infrastructure burden:

  • Vercel and Netlify: ideal for Next.js and serverless functions (episode 27).
  • Railway and Render: deploy from the repository with auto-deploy, including databases.
  • Fly.io: close to bare metal, global distribution.
  • AWS Lambda + API Gateway: pure serverless on AWS.

A quick Railway deploy is just railway init && railway up.

Choose based on your needs: for full-stack Next.js, Vercel is very natural; for a standalone Node service with a database, Railway and Render simplify a lot.

Containerization

Docker Setup and Multi-Stage Build

Multi-stage builds produce small, safe images — one stage for building, one for running:

Multi-stage Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json bun.lock ./
RUN npm ci
COPY . .
RUN npm run build
 
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/package.json ./
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
EXPOSE 4000
CMD ["node", "dist/index.js"]
Build and run the image
docker build -t api-graphql .
docker run -p 4000:4000 --env-file .env.production api-graphql

Docker Compose for Development

For development, Docker Compose runs the whole stack at once:

docker-compose.yml
services:
  api:
    build: .
    ports:
      - "4000:4000"
    environment:
      DATABASE_URL: postgres://user:pass@db:5432/app
    depends_on:
      - db
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: pass

Kubernetes Deployment

Deployment and Service Manifests

For enterprise scale, Kubernetes manages deployment, scaling, and recovery:

Deployment manifest
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-graphql
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api-graphql
  template:
    metadata:
      labels:
        app: api-graphql
    spec:
      containers:
        - name: api
          image: registry.example.com/api-graphql:1.2.3
          ports:
            - containerPort: 4000
          livenessProbe:
            httpGet: { path: /health/live, port: 4000 }
          readinessProbe:
            httpGet: { path: /health/ready, port: 4000 }

The liveness and readiness health checks (episode 24) tell Kubernetes when a container is healthy enough to receive traffic.

ConfigMaps, Secrets, and Autoscaling

Separate configuration from secrets:

  • ConfigMap for non-secret values (log levels, feature flags).
  • Secret for database credentials and API keys.
  • Horizontal Pod Autoscaler to add replicas based on CPU.
Horizontal Pod Autoscaler
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-graphql
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-graphql
  minReplicas: 3
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70

Serverless Considerations

Cold Starts and Stateless Design

Serverless (Lambda, Cloud Functions) brings automatic scaling benefits, but has trade-offs:

  • Cold starts: a new instance takes longer to respond to the first request. Reduce this with a small bundle and light dependencies.
  • Stateless design: don't store state in memory across requests; use Redis.
  • Connection pooling: don't open a database connection per request; use pooling or a serverless database (episode 37).

Environment Management and Migrations

Environment Variables and Secrets

Create per-environment configuration: development, staging, production. Store secrets in a safe place — AWS Secrets Manager, Vault, or the platform's built-in features — and never in the repository. Reference secrets via environment variables at runtime, not hardcoded in code.

Database Migrations

Run migrations safely before new traffic is accepted:

Prisma migration
npx prisma migrate deploy

For zero-downtime deployments, separate the app deployment from the database migration: run the expand migration (adding columns) first, then release the new app, then migrate the contract. This pattern is explained further in episodes 32 and 35.

Conclusion

Key takeaways:

  • Choose managed platforms (Vercel, Railway, Render) to start; Kubernetes for enterprise.
  • Multi-stage Docker builds produce small production images.
  • Kubernetes manifests use health checks for healthy orchestration.
  • Serverless demands stateless design and attention to cold starts.
  • Separate ConfigMaps from Secrets; never commit secrets.
  • Run database migrations separately for zero downtime.

In the next episode, episode 32, you'll learn about CI/CD for GraphQL — setting up pipelines with GitHub Actions and GitLab CI, automated testing, schema checks to block breaking changes, deployment automation with blue-green and canary strategies, code quality gates, and release management with semantic versioning. Deploys will become a safe routine!

Learn GraphQL - Deploying GraphQL to Production | Learn GraphQL