A modern CI/CD pipeline removes the anxiety from deployments. In this guide we’ll containerise a MERN application with Docker, push images to Amazon ECR, and deploy to ECS Fargate using a GitHub Actions workflow — automated, zero-downtime, on every push to main.
mern-app/
backend/
Dockerfile
src/
frontend/
Dockerfile
src/
docker-compose.yml ← local development
.github/
workflows/
deploy.yml
# backend/Dockerfile
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM node:20-alpine AS runner
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY src ./src
EXPOSE 4000
USER node
CMD ["node", "src/index.js"]
# frontend/Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine AS runner
COPY --from=builder /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
services:
mongo:
image: mongo:7
volumes:
- mongo-data:/data/db
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: secret
backend:
build: ./backend
ports:
- "4000:4000"
environment:
MONGO_URI: mongodb://root:secret@mongo:27017/myapp?authSource=admin
depends_on:
- mongo
frontend:
build: ./frontend
ports:
- "3000:80"
depends_on:
- backend
volumes:
mongo-data:
# .github/workflows/deploy.yml
name: Deploy to AWS ECS
on:
push:
branches: [main]
env:
AWS_REGION: us-east-1
ECR_REGISTRY: ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.us-east-1.amazonaws.com
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Login to ECR
uses: aws-actions/amazon-ecr-login@v2
- name: Build, tag, push backend
run: |
docker build -t $ECR_REGISTRY/mern-backend:${{ github.sha }} ./backend
docker push $ECR_REGISTRY/mern-backend:${{ github.sha }}
- name: Build, tag, push frontend
run: |
docker build -t $ECR_REGISTRY/mern-frontend:${{ github.sha }} ./frontend
docker push $ECR_REGISTRY/mern-frontend:${{ github.sha }}
- name: Deploy to ECS
run: |
aws ecs update-service \
--cluster mern-cluster \
--service mern-backend \
--force-new-deployment
aws ecs update-service \
--cluster mern-cluster \
--service mern-frontend \
--force-new-deployment
Configure your ECS service with a rolling update deployment type and a minimum healthy percent of 100% — ECS will launch new tasks before draining old ones, giving you zero-downtime deploys automatically.
aws ecs create-service \
--cluster mern-cluster \
--service-name mern-backend \
--deployment-configuration "minimumHealthyPercent=100,maximumPercent=200" \
--deployment-controller type=ECS
With this pipeline, every git push to main triggers a full build, test, and deploy in about 4 minutes. Your team can ship confidently multiple times per day.