How to Deploy Angular SSR App on Google Cloud Run [Complete Guide]

Deploying an Angular SSR (Angular Universal) app on Google Cloud Run is one of the best ways to achieve scalability, SEO optimization, and cost-efficiency for your web application. Unlike traditional static hosting, SSR (Server-Side Rendering) ensures that your Angular app loads faster, ranks better on search engines, and provides a smoother experience for users.

With Google Cloud Run, you get a fully managed, serverless platform that automatically scales your Angular SSR app up or down based on traffic — and you only pay for what you use. Whether you’re deploying directly from source code or using a Docker image, Cloud Run makes the process simple and production-ready.

Deploy Angular SSR App on Google Cloud Run

At a glance (TL;DR)

  • Add SSR: ng add @angular/ssr
  • Local check: npm run build && npm run serve:ssr
  • Easiest deploy (no Dockerfile): gcloud run deploy --source .
  • Or Docker deploy: build image → push to Artifact Registry → gcloud run deploy

Prerequisites

  • Node.js 18 or 20 LTS, Angular CLI 17+
  • A Google Cloud project (with billing enabled)
  • gcloud CLI installed & authenticated
  • Region you want (example uses us-central1)
gcloud auth login
gcloud config set project YOUR_PROJECT_ID
gcloud config set run/region us-central1

1) Add SSR to your Angular app

From your project root:

ng add @angular/ssr

This sets up the server build and adds helpful scripts.

Package.json scripts (verify / add)

Make sure you have these (adjust name my-app if yours differs):

{
  "scripts": {
    "build:ssr": "ng build",
    "serve:ssr": "node dist/my-app/server/server.mjs",
    "start": "node dist/my-app/server/server.mjs",
    "gcp-build": "npm run build:ssr"
  },
  "engines": { "node": ">=20 <21" }
}

gcp-buid is a special script the Google Buildpacks run at build time — it ensures the SSR bundle is built inside the container.

Make sure the server respects Cloud Run’s port

Cloud Run injects PORT (default 8080). The generated server typically reads it automatically, but if you have a custom server.ts, ensure:

const port = Number(process.env.PORT) || 8080;
server.listen(port, () => console.log(`Listening on ${port}`));

2) Test locally

npm install
npm run build
npm run serve:ssr
# open http://localhost:4000 (or whatever your script logs)

Option A — Deploy from source (no Dockerfile, simplest)

This uses Google Buildpacks. They will:

  • Install deps
  • Run gcp-build (our SSR build)
  • Use npm start as the container start command

a. Enable required APIs

gcloud services enable run.googleapis.com cloudbuild.googleapis.com artifactregistry.googleapis.com

b. Deploy

From your project root:

gcloud run deploy my-app --source . --allow-unauthenticated

That’s it. Cloud Run builds, deploys, and gives you a live HTTPS URL.

Update env vars later (optional):

gcloud run services update my-app \
  --update-env-vars NODE_ENV=production,API_URL=https://api.example.com

Option B — Dockerfile deploy (more control, smaller cold starts)

Create a multi-stage Dockerfile

Place Dockerfile at project root:

# ---- Build stage ----
FROM node:20-alpine AS build
WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .
# Build Angular SSR (browser + server)
RUN npm run build

# ---- Runtime stage ----
FROM node:20-alpine
ENV NODE_ENV=production
WORKDIR /app

# Copy built SSR output
COPY --from=build /app/dist/my-app /app/dist/my-app

# Cloud Run injects PORT. Angular SSR server reads it.
EXPOSE 4200
CMD ["node", "dist/my-app/server/server.mjs"]

i. Deploy from Google Cloud Console

a. Login to Google Cloud Console

Open 👉 https://console.cloud.google.com/ and select your current project

b. Navigate to Cloud Run

Search for “Cloud Run” and select or open this link https://console.cloud.google.com/run

c. Deploy Container

Select the “Deploy container” in Cloud Run

Now you have to create service. Select the “GitHub” if you want to deploy the source code from git repository or else select the other options based on your requirement. In this example, I will show how to deploy using GitHub

  • Next click Set up with Cloud Build button.
  • New window will open, where you have to Authenticate your GitHub and select Repository

Click Next after selecting Repository, you will see the options to configure build options.

  • Branch: Give the branch name of the GitHub Repo
  • Build Type: Select Dockerfile if you want to build using Docker and give the Docker file name, which is in your source code and click Save.

Now you will see the Endpoint URL is created.

Select the Authentication based on your Requirement

You can keep the other details as it is and select Create button to create service. Then service will start creating.

It will take few min to build the code and deploy.

After Successful deployment, you can open the URL and verify.

ii. Deploy from gcloud CLI

Build & push image to Artifact Registry

(You only need to create the repo once.)

# Create Docker repo (one time)
gcloud artifacts repositories create web-apps \
  --repository-format=docker \
  --location=asia-south1 \
  --description="Docker images for web apps"

# Build & push
gcloud builds submit --tag asia-south1-docker.pkg.dev/YOUR_PROJECT_ID/web-apps/my-app:1.0.0

Deploy to Cloud Run

gcloud run deploy my-app \
  --image asia-south1-docker.pkg.dev/YOUR_PROJECT_ID/web-apps/my-app:1.0.0 \
  --allow-unauthenticated \
  --port 8080

Post-deploy tuning (recommended)

  • Min instances (cut cold starts): gcloud run services update my-app --min-instances 1
  • CPU & memory (SSR is CPU-heavy): gcloud run services update my-app --cpu 1 --memory 512Mi --concurrency 10 If you have spikes and heavier pages, try --cpu 2 or lower concurrency.
  • Custom domain & HTTPS: map your domain in Cloud Run console or via gcloud beta run domain-mappings.

Optional: set up CI/CD with Cloud Build

Create cloudbuild.yaml to auto-deploy on main push (Dockerfile path):

steps:
  - name: gcr.io/cloud-builders/docker
    args: ["build", "-t", "asia-south1-docker.pkg.dev/$PROJECT_ID/web-apps/my-app:$COMMIT_SHA", "."]
  - name: gcr.io/cloud-builders/docker
    args: ["push", "asia-south1-docker.pkg.dev/$PROJECT_ID/web-apps/my-app:$COMMIT_SHA"]
  - name: gcr.io/google.com/cloudsdktool/cloud-sdk
    entrypoint: gcloud
    args:
      [
        "run","deploy","my-app",
        "--image","asia-south1-docker.pkg.dev/$PROJECT_ID/web-apps/my-app:$COMMIT_SHA",
        "--region","asia-south1",
        "--allow-unauthenticated",
        "--port","8080"
      ]
images:
  - asia-south1-docker.pkg.dev/$PROJECT_ID/web-apps/my-app:$COMMIT_SHA

Then add a Cloud Build trigger on your repo’s main branch.

Troubleshooting

  • App starts but Cloud Run shows 502 / 404
    Ensure the app listens on PORT (8080). Logs will say if it’s bound to a different port.
  • Buildpacks deploy succeeds but 404 on start
    Check that gcp-build produces dist/my-app/server/server.mjs. Without that file, npm start can’t serve SSR.
  • “Cannot find module …” at runtime
    In Docker builds, make sure runtime image includes node_modules (after npm prune --omit=dev) and the dist folder.
  • Cold starts are noticeable
    Set --min-instances 1 and keep image small (multi-stage, prune dev deps).
  • Memory exceeded
    Bump memory to 1Gi and reduce --concurrency to ~5–10 for heavy pages.
  • Static assets 404
    Angular’s SSR server serves /browser assets. Verify they exist under dist/my-app/browser and your server routes don’t block them.

Cost & scaling

Cloud Run scales to zero when idle (unless you set min instances), and scales out per request load. You pay only for CPU/memory while requests are handled — ideal for SSR traffic patterns.

Copy-paste checklist

# 0) Project & region
gcloud config set project YOUR_PROJECT_ID
gcloud config set run/region asia-south1
gcloud services enable run.googleapis.com cloudbuild.googleapis.com artifactregistry.googleapis.com

# 1) Add SSR
ng add @angular/ssr

# 2) Scripts (package.json)
# "gcp-build": "npm run build:ssr"
# "start": "node dist/my-app/server/server.mjs"

# 3A) EASIEST: Source deploy
gcloud run deploy my-app --source . --allow-unauthenticated

#   — OR —

# 3B) Docker deploy
gcloud artifacts repositories create web-apps --repository-format=docker --location=asia-south1
gcloud builds submit --tag asia-south1-docker.pkg.dev/YOUR_PROJECT_ID/web-apps/my-app:1.0.0
gcloud run deploy my-app --image asia-south1-docker.pkg.dev/YOUR_PROJECT_ID/web-apps/my-app:1.0.0 --allow-unauthenticated --port 8080

# 4) Tuning
gcloud run services update my-app --min-instances 1 --cpu 1 --memory 512Mi --concurrency 10

Bonus: quick NGINX edge cache (optional)

If your SSR output is cacheable for anonymous users, place Cloud Run behind a Cloud Load Balancer + Cloud CDN for static + HTML edge caching. This keeps SSR responsive during traffic spikes.

Leave a Reply

Your email address will not be published. Required fields are marked *