Skip to main content
The project ships with a multi-stage Dockerfile that produces a lean production image containing only the compiled output and runtime dependencies.

Dockerfile stages

The build is split into four stages to minimise the final image size:
StageBase imagePurpose
development-dependencies-envnode:20-alpineInstall all dependencies (including devDependencies) for the build step
production-dependencies-envnode:20-alpineInstall only production dependencies (--omit=dev)
build-envnode:20-alpineRun npm run build using the dev dependencies
(final)node:20-alpineCopy production deps + compiled build; start the server
Dockerfile
FROM node:20-alpine AS development-dependencies-env
COPY . /app
WORKDIR /app
RUN npm ci

FROM node:20-alpine AS production-dependencies-env
COPY ./package.json package-lock.json /app/
WORKDIR /app
RUN npm ci --omit=dev

FROM node:20-alpine AS build-env
COPY . /app/
COPY --from=development-dependencies-env /app/node_modules /app/node_modules
WORKDIR /app
RUN npm run build

FROM node:20-alpine
COPY ./package.json package-lock.json /app/
COPY --from=production-dependencies-env /app/node_modules /app/node_modules
COPY --from=build-env /app/build /app/build
WORKDIR /app
CMD ["npm", "run", "start"]
The final image exposes the server on port 3000.

Build and run

1

Build the image

docker build -t stripe-payment-app .
2

Run the container

Pass environment variables at runtime using --env or --env-file:
docker run \
  --publish 3000:3000 \
  --env STRIPE_SECRET_KEY=sk_live_... \
  --env STRIPE_WEBHOOK_SECRET=whsec_... \
  --env SESSION_SECRET=your-session-secret \
  stripe-payment-app
The app is now reachable at http://localhost:3000.
3

Verify the container is running

docker ps
docker logs <container-id>
Do not bake secrets into the image at build time. Always inject them as environment variables at runtime so the same image can be promoted across environments.

Deploying to cloud platforms

The image runs on any platform that supports OCI-compatible containers. Push the image to your registry, then deploy using the platform-specific command.
# Push to ECR, then update the ECS service
aws ecr get-login-password | docker login --username AWS --password-stdin <account>.dkr.ecr.<region>.amazonaws.com
docker tag stripe-payment-app <account>.dkr.ecr.<region>.amazonaws.com/stripe-payment-app:latest
docker push <account>.dkr.ecr.<region>.amazonaws.com/stripe-payment-app:latest
aws ecs update-service --cluster <cluster> --service <service> --force-new-deployment

Build docs developers (and LLMs) love