- Write-ups
- Deploying a Next.js Application to Google Cloud Run

Deploying a Next.js Application to Google Cloud Run
Google Cloud Run is a serverless platform for deploying containerized applications with automatic scaling and built-in HTTPS. I use it to deploy Next.js applications with Docker and automate deployments using Google Cloud Build for a reliable CI/CD workflow.
Contents
Contents
Overview
Google Cloud Run provides a fully managed serverless platform for deploying containerized applications without managing infrastructure. By combining Docker, Cloud Run, and Cloud Build, you can automate deployments, enable continuous integration, and scale your Next.js application based on demand.
This guide demonstrates how to containerize a Next.js application, deploy it to Cloud Run, and configure an automated CI/CD pipeline using GitHub and Google Cloud Build.
Why Google Cloud Run?
Google Cloud Run is an excellent deployment platform for modern web applications because it removes the complexity of managing servers while providing reliable performance and automatic scaling.
Key Benefits
- Fully managed serverless hosting
- Automatic scaling based on traffic
- Container-based deployments with Docker
- Continuous deployment using Cloud Build
- Pay only for resources consumed
- Built-in HTTPS and secure networking
- Easy integration with GitHub
Prerequisites
Before deployment, make sure you have:
- A Google Cloud project
- Billing enabled
- A Next.js application
- Docker installed
- A GitHub repository
- Google Cloud CLI (optional for local deployments)
Configure Your Google Cloud Project
Create a new Google Cloud project or select an existing one.
Enable the required services:
- Cloud Run API
- Cloud Build API
- Artifact Registry (or Container Registry)
- Cloud Logging API (optional)
These services provide the infrastructure needed to build, store, and deploy your application.
Prepare Your Next.js Application
Containerize your application by creating a Dockerfile in the project root.
The Dockerfile defines:
- Base image
- Dependency installation
- Application build
- Production startup
# Step 1: Base Image
FROM node:23.0.0-alpine3.20 AS base
# Install compatibility package
RUN apk add --no-cache libc6-compat
# Set working directory
WORKDIR /app
# Step 2: Dependencies Layer
FROM base AS deps
COPY package*.json ./
# Install dependencies
RUN npm ci
# Step 3: Build Layer
FROM base AS builder
WORKDIR /app
# Copy dependencies from previous layer
COPY --from=deps /app/node_modules ./node_modules
# Copy the rest of the app files
COPY . .
# Disable Next.js telemetry
ENV NEXT_TELEMETRY_DISABLED 1
# Build the Next.js application
RUN npm run build
# Step 4: Runner Layer
FROM base AS runner
WORKDIR /app
# Set environment to production
ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1
ENV PORT 3000 # Use port 3000 as per your Cloud Run setup
# Create non-root user and group
RUN addgroup --system --gid 1001 nodejs \
&& adduser --system --uid 1001 nextjs
# Copy necessary files for runtime
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
# Switch to non-root user
USER nextjs
# Expose port 3000
EXPOSE 3000
# Start the application
CMD ["npm", "start"]Test the Container (Optional)
Before deploying, build and run the container locally to verify that everything works correctly.
# 1. Build the Docker image from your Dockerfile
docker build -t nextjs-app .
# 2. Run the container and map the ports
docker run -p 3000:3000 nextjs-appDeploy to Google Cloud Run
Open the Cloud Run service in the Google Cloud Console and create a new service.
Configure the deployment using:
- Container image
- Deployment region
- Service name
- Public accessibility
- Port configuration (3000)
Enable unauthenticated access if the application should be publicly accessible.
Once deployment is complete, Cloud Run generates a public HTTPS endpoint for your application.
Configure Service Settings
Before finalizing the deployment, review the service configuration.
Recommended settings include:
- Port: 3000
- Automatic scaling enabled
- Maximum instances based on expected traffic
- Appropriate CPU and memory allocation
- Environment variables (if required)
These settings help optimize performance while controlling operational costs.
Configure CI/CD with Google Cloud Build
To automate future deployments, configure Google Cloud Build to build and deploy the application whenever new code is pushed to GitHub.
Create a cloudbuild.yaml file in the project root that defines the build and deployment pipeline.
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: my-service
namespace: 'MY_PROJECT_NAMESPACE'
selfLink: /apis/serving.knative.dev/v1/namespaces/MY_PROJECT_NAMESPACE/services/my-service
uid: unique-id-placeholder
resourceVersion: version-placeholder
generation: 1
creationTimestamp: '2024-11-12T00:00:00.000000Z'
labels:
commit-sha: placeholder-sha
gcb-build-id: build-id-placeholder
gcb-trigger-id: trigger-id-placeholder
gcb-trigger-region: global
managed-by: cloud-build-deploy-cloud-run
cloud.googleapis.com/location: us-central1
annotations:
serving.knative.dev/creator: user@example.com
serving.knative.dev/lastModifier: project-id-compute@developer.gserviceaccount.com
run.googleapis.com/client-name: gcloud
run.googleapis.com/client-version: placeholder-version
run.googleapis.com/operation-id: operation-id-placeholder
run.googleapis.com/ingress: all
run.googleapis.com/ingress-status: all
run.googleapis.com/urls: >-
["https://my-service-MY_PROJECT_NAMESPACE.us-central1.run.app","https://my-service-unique-id-placeholder.a.run.app"]
spec:
template:
metadata:
labels:
client.knative.dev/nonce: nonce-placeholder
commit-sha: placeholder-sha
gcb-build-id: build-id-placeholder
gcb-trigger-id: trigger-id-placeholder
gcb-trigger-region: global
managed-by: cloud-build-deploy-cloud-run
run.googleapis.com/startupProbeType: Default
annotations:
autoscaling.knative.dev/maxScale: '10'
run.googleapis.com/client-name: gcloud
run.googleapis.com/client-version: placeholder-version
run.googleapis.com/startup-cpu-boost: 'true'
spec:
containerConcurrency: 80
timeoutSeconds: 300
serviceAccountName: project-id-compute@developer.gserviceaccount.com
containers:
- name: main-container
image: >-
us-central1-docker.pkg.dev/my-project/cloud-run-source-deploy/my-service/image:placeholder-sha
ports:
- name: http1
containerPort: 3000
env:
- name: NEXT_PUBLIC_SANITY_PROJECT_ID
value: my-sanity-project
- name: NEXT_PUBLIC_SANITY_DATASET
value: production
- name: RESEND_API_KEY
value: placeholder-key
resources:
limits:
cpu: 1000m
memory: 512Mi
startupProbe:
timeoutSeconds: 240
periodSeconds: 240
failureThreshold: 1
tcpSocket:
port: 3000
traffic:
- percent: 100
latestRevision: trueCreate a Build Trigger
Navigate to:
Cloud Build → Triggers
Create a new trigger and connect your GitHub repository.
Configure:
- Repository
- Deployment branch
- Trigger event
- Build configuration using cloudbuild.yaml
From this point forward, every push to the selected branch automatically starts a new deployment.
[Image: Cloud Build Trigger]
Verify the Deployment
Commit and push your latest changes to GitHub.
Google Cloud Build automatically:
- Clones the repository
- Builds the Docker image
- Pushes the container image
- Deploys the latest version to Cloud Run
Monitor deployment progress from Cloud Build → History and verify that the updated application is live.
Conclusion
Google Cloud Run offers a modern and efficient deployment workflow for Next.js applications by combining serverless infrastructure with containerized deployments. When paired with Docker and Google Cloud Build, it provides automated CI/CD, seamless scaling, and reliable production deployments with minimal operational overhead.
For freelance and production projects, I frequently recommend Google Cloud Run because it enables fast deployments, reduces infrastructure management, and automatically scales applications as traffic grows.


