DEV Community

Dany Paredes
Dany Paredes

Posted on Originally published at danywalls.com on

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 :

  1. How do you serve _next/static assets at edge speed without hammering your container?
  2. How do you manage API keys and database credentials securely?
  3. How do you eliminate cold starts when traffic spikes?
  4. 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;

Enter fullscreen mode Exit fullscreen mode

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"

Enter fullscreen mode Exit fullscreen mode

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"

Enter fullscreen mode Exit fullscreen mode

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"

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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'

Enter fullscreen mode Exit fullscreen mode

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)