ZVN

Deploying a React Router 7 App to Google Cloud Run with Docker

React Router 7 in framework mode builds to a Node server, which means it needs somewhere to run. Cloud Run is a great fit: give it a container and it handles the rest. In this post, we'll go from a working app to a live URL.

Why Cloud Run?

  • Scales to zero—you pay nothing when nobody visits
  • Scales up automatically when traffic spikes
  • All it needs is a Dockerfile

The Server

A React Router 7 template already comes with everything we need. The build outputs a server bundle, and react-router-serve runs it:

{
"scripts": {
"build": "react-router build",
"start": "react-router-serve ./build/server/index.js"
}
}

One detail matters for Cloud Run: it tells your container which port to use through the PORT env variable. react-router-serve respects it out of the box, so there's nothing to configure.

The Dockerfile

A two-stage build keeps the final image small—dev dependencies are used to build, then left behind:

FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=build /app/build ./build
CMD ["npm", "run", "start"]

And a .dockerignore so local artifacts don't leak into the image:

node_modules
build
.git
.env

Deploying

With the gcloud CLI installed and authenticated, one command builds and deploys straight from source:

gcloud run deploy my-app \
--source . \
--region us-central1 \
--allow-unauthenticated

Cloud Run uploads your code, builds the Dockerfile in the cloud, and hands back a public URL. Every deploy after this is the same one command.

Conclusion

A Dockerfile, a .dockerignore, and one gcloud command—that's the whole deployment. Cloud Run takes care of scaling, HTTPS, and the infrastructure you'd rather not manage.

Don't forget your env variables—your local .env doesn't come along for the ride. Pass them with --set-env-vars on deploy, or set them on the service in the Cloud Run console. 😉

© Copyright Eli Zevin