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=1
4. 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
Top comments (0)