Next.js on Google Cloud Run: Production Caching, Secrets, and Zero Cold Starts

In my previous guide, Moving from Vercel Next.js to Google Cloud Run, we walked through setting up standalone Docker builds and deploying to Cloud Run to achieve predictable $0 hosting.
Once your Next.js application is running in a container, the next step is making it truly production-ready:
- How do you serve
_next/staticassets at edge speed without hammering your container? - How do you manage API keys and database credentials securely?
- How do you eliminate cold starts when traffic spikes?
- How do you automate deployment pipelines with Google Cloud Build?
Here is the architectural blueprint for running high-performance Next.js on Google Cloud Run.
1. Edge Caching & Cloud CDN for Static Assets ⚡
When you run Next.js on Vercel, static assets in _next/static and public/ are served automatically from edge points of presence. On Cloud Run, every uncached request spins up a container CPU cycle.
To prevent container load and ensure sub-50ms asset delivery, configure Cache-Control headers in next.config.ts:
// next.config.ts
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
output: "standalone",
async headers() {
return [
{
// Cache immutable static bundles for 1 year at the edge
source: "/_next/static/:path*",
headers: [
{
key: "Cache-Control",
value: "public, max-age=31536000, immutable",
},
],
},
{
// Cache public images and icons for 24 hours
source: "/images/:path*",
headers: [
{
key: "Cache-Control",
value: "public, max-age=86400, stale-while-revalidate=43200",
},
],
},
];
},
};
export default nextConfig;When placed behind Cloudflare or a Google Cloud Load Balancer with Cloud CDN enabled, static assets are cached at the edge, reducing container requests by over 85%.
2. Managing Secrets with Google Secret Manager 🔐
Never bake .env files or API secrets into Docker images. Instead, store them in Google Secret Manager and mount them into your Cloud Run service at startup.
Step 1: Create the Secret in GCP
echo -n "sk_live_my_super_secret_api_key" | gcloud secrets create STRIPE_API_KEY \
--data-file=- \
--replication-policy="automatic"Step 2: Grant Permissions to the Cloud Run Service Account
PROJECT_ID=$(gcloud config get-value project)
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
gcloud secrets add-iam-policy-binding STRIPE_API_KEY \
--member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
--role="roles/secretmanager.secretAccessor"Step 3: Mount Secrets in the Deployment Command
gcloud run deploy nextjs-blog \
--image gcr.io/${PROJECT_ID}/nextjs-blog:latest \
--region us-central1 \
--set-secrets="STRIPE_SECRET_KEY=STRIPE_API_KEY:latest"In your Next.js code (process.env.STRIPE_SECRET_KEY), the value is accessible synchronously as a standard environment variable.
3. Eliminating Cold Starts 🚀
Cloud Run scales down to zero instances when idle, saving you money. However, the first request after an idle period experiences a cold start.
Here is how to reduce cold start latency from 4 seconds down to under 300ms:
| Technique | Command / Setting | Impact |
|---|---|---|
| Standalone Output | output: 'standalone' in Next.js | Container drops from 2.1GB to 120MB |
| Startup CPU Boost | --cpu-boost flag | Allocates 200% CPU during container boot |
| Minimum Instances | --min-instances=1 | Keeps 1 container warm at all times (optional) |
| Concurrency Tuning | --concurrency=80 | Handles up to 80 requests simultaneously per container |
Deploy with startup CPU boost enabled:
gcloud run deploy nextjs-blog \
--image gcr.io/${PROJECT_ID}/nextjs-blog:latest \
--region us-central1 \
--cpu-boost \
--concurrency=80 \
--memory=512Mi \
--cpu=14. Automated CI/CD with Cloud Build 🛠️
Instead of deploying manually from your terminal, set up a cloudbuild.yaml file in your repository:
# cloudbuild.yaml
steps:
# 1. Build Docker image with Kaniko cache
- name: 'gcr.io/kaniko-project/executor:latest'
args:
- '--destination=gcr.io/$PROJECT_ID/nextjs-blog:$COMMIT_SHA'
- '--destination=gcr.io/$PROJECT_ID/nextjs-blog:latest'
- '--cache=true'
- '--cache-ttl=24h'
# 2. Deploy container to Google Cloud Run
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
entrypoint: gcloud
args:
- 'run'
- 'deploy'
- 'nextjs-blog'
- '--image=gcr.io/$PROJECT_ID/nextjs-blog:$COMMIT_SHA'
- '--region=us-central1'
- '--platform=managed'
- '--allow-unauthenticated'
- '--cpu-boost'
images:
- 'gcr.io/$PROJECT_ID/nextjs-blog:$COMMIT_SHA'
- 'gcr.io/$PROJECT_ID/nextjs-blog:latest'Connect your GitHub repository in the Google Cloud Console under Cloud Build > Triggers. Every push to main automatically builds, tests, and deploys your Next.js application in under 90 seconds.
Conclusion & Architecture Summary 🎯
Running Next.js on Google Cloud Run gives you enterprise-grade infrastructure without runaway bills:
- Cloud CDN / Cloudflare Cache-Control protects your containers and speeds up static assets.
- Secret Manager keeps tokens and sensitive credentials secure.
- Startup CPU Boost eliminates cold starts.
- Cloud Build automates production deployment with zero manual steps.
Ready to migrate? Check out the initial guide: Moving from Vercel Next.js to Google Cloud Run: A Cost and Architecture Guide.
Photo by Robson Hatsukami Morgan on Unsplash
Explore more in-depth guides and real-world architectures in the Cloud series.
Frequently Asked Questions
How do you handle static asset caching for Next.js on Google Cloud Run?
Pair your Cloud Run service with Google Cloud CDN or Cloudflare. Set immutable Cache-Control headers on static chunks (_next/static) so edge caches serve static assets directly without hitting your container instances.
How do you inject environment variables securely from Google Secret Manager?
Use the --set-secrets flag in the gcloud run deploy command to mount secrets as environment variables directly at runtime, granting the Cloud Run service account the Secret Manager Secret Accessor role.
How can you minimize cold starts in Next.js on Cloud Run?
Keep container images minimal with Next.js standalone mode (under 120MB), enable startup CPU boost with --cpu-boost, and configure --min-instances=1 during peak business hours.
Can you automate Next.js deployments to Cloud Run with Cloud Build?
Yes. Create a cloudbuild.yaml file in your repository and set up a Cloud Build GitHub trigger to build, push to Artifact Registry, and deploy to Cloud Run automatically on every push.
Related Articles
Moving from Vercel Next.js to Google Cloud Run: A Cost and Architecture Guide
Why I migrated my Next.js projects from Vercel to Google Cloud Run, how the standalone Docker build works, and how to stay on the free tier.
How To Get Started with Docker: A Step-by-Step Guide for Beginners
Being ready to deploy your apps with Docker is a higher-demand knowledge today, and this article will guide you (and me) from zero to surviving with Docker. The guide's key features are: Install and run the docker Create and build images Mount vol...
My Newsletter Went to Spam: How I Fixed Email Deliverability for Free with Cloudflare
A friend told me my emails were hitting his Spam folder. Here is how I fixed my deliverability using Cloudflare Email Routing and custom domain authentication for $0.
Real Software. Real Lessons.
I share the lessons I learned the hard way, so you can either avoid them or be ready when they happen.
Join 13,800+ developers and readers.
No spam ever. Unsubscribe at any time.