Deploying a Vite React App to Google Cloud Run (Step-by-Step)
A production-tested walkthrough for shipping a Vite + React single-page app to Google Cloud Run with Cloud Build, Nginx, and sensible caching headers.
Why Cloud Run for a static SPA?
Cloud Run isn't only for containerized backend APIs. For a marketing site or a lightweight SPA, it's a surprisingly clean fit: you get free TLS, custom domains, autoscaling to zero, and regional failover without ever touching a Kubernetes cluster. At our typical traffic volume, the bill rounds to zero.
This is the exact workflow we use on our own naaocreations.com site, and it's the same one we hand to early-stage clients who need to go live tomorrow.
The stack
- Vite + React for the app
- Nginx (alpine) to serve the built assets
- Cloud Build for CI from
main - Cloud Run for hosting
- Artifact Registry for the container image
Dockerfile
A two-stage build keeps the final image small — about 25 MB for most SPAs:
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:1.27-alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 8080
CMD ["nginx", "-g", "daemon off;"]
Cloud Run listens on the PORT env var (defaults to 8080), so the Nginx listen 8080; directive matters.
nginx.conf
Serve / from index.html, cache static assets aggressively, don't cache HTML:
server {
listen 8080;
root /usr/share/nginx/html;
index index.html;
gzip on;
gzip_types text/plain text/css application/javascript application/json;
location / { try_files $uri $uri/ /index.html; }
location ~* \.(js|css|svg|png|woff2|ico)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-store";
}
}
cloudbuild.yaml
steps:
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'us-central1-docker.pkg.dev/$PROJECT_ID/apps/naao-site:$SHORT_SHA', '.']
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'us-central1-docker.pkg.dev/$PROJECT_ID/apps/naao-site:$SHORT_SHA']
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
entrypoint: gcloud
args:
- run
- deploy
- naao-site
- --image=us-central1-docker.pkg.dev/$PROJECT_ID/apps/naao-site:$SHORT_SHA
- --region=us-central1
- --allow-unauthenticated
- --platform=managed
- --cpu=1
- --memory=256Mi
- --min-instances=0
- --max-instances=5
Gotchas we hit
- Port mismatch. Cloud Run injects
PORT. If your Nginx listens on 80, you'll get 500s. Listen on 8080 explicitly (or templatize withenvsubst). - SPA 404s on deep links are always Nginx misconfig. The
try_files ... /index.htmlfallback is mandatory. - Min-instances = 0 causes cold starts (~200 ms with Nginx). For a marketing site, this is fine. For a real app, set it to 1.
- Environment variables injected at build time must be baked into the bundle with
VITE_prefix. Anything secret stays server-side.
Cost
For our traffic, GCP bills < $1/month. Cloud Build's first 120 build-minutes/day are free, and Cloud Run's free tier covers the invocations.
Next steps
Most of our sites evolve from pure SPA to SSG once we need SEO. If you're headed that direction, see our follow-up on swapping vite build for vite-react-ssg build — the Docker and Cloud Run pieces don't change.
Need help shipping your own app to production? Talk to our team.
Our team ships this exact work for clients every week.
We cover Cloud Solutions, and Web Applications. Cloud-native deployments on GCP and AWS.
Related reading
Adding Google Gemini to a React App: A Practical Guide with Code
How to plug Google Gemini into a real React app — streaming, tool use, cost controls, and the security pitfalls we see most often.
React Native vs Flutter in 2026: Which Should Your Startup Choose?
After shipping mobile apps on both, here is how we pick between React Native and Flutter for real clients in 2026 — decision framework included.
The Real Cost of Building an MVP App in 2026 (Mobile + Web)
Line-item breakdown of what it actually costs to ship a production MVP in 2026 — design, dev, infra, compliance, and the things founders forget.