Google Cloud

Building a SaaS Backend on Cloud Run + Firestore: Complete GCP Tutorial

2026-05-24
NicheeLab Editorial Team

Cloud Run + Firestore is the go-to stack for modern SaaS backends. Serverless, fully managed, and with a generous free tier, it scales from solo projects to production SaaS. This article walks through everything from multi-tenant design to billing with practical implementation examples.

Overall Architecture

Web/Mobile (React/Flutter)
        |
   Firebase Auth (authentication)
        |
   Firebase Hosting (frontend CDN) -> Cloud Run (API)
                                          |
                                          v
                              Firestore (primary DB)
                              Cloud Storage (files)
                              Pub/Sub (async processing)
                              Cloud Tasks (deferred work)
                              Stripe Webhook → Cloud Run
                              SendGrid (email)
                              Cloud Scheduler (scheduled batch)

Step 1: Firestore Multi-Tenant Design

// Structure
/tenants/{tenant_id}
  /users/{user_id}
  /subscriptions/{sub_id}
  /resources/{resource_id}

// or
/tenants/{tenant_id}/{collection}/{doc}

// Security Rules (example)
match /tenants/{tenant_id}/{document=**} {
  allow read, write: if request.auth.token.tenant_id == tenant_id;
}

Step 2: Cloud Run API (Node.js / Express)

import express from "express";
import { initializeApp, applicationDefault } from "firebase-admin/app";
import { getAuth } from "firebase-admin/auth";
import { getFirestore } from "firebase-admin/firestore";

initializeApp({ credential: applicationDefault() });
const app = express();
app.use(express.json());

// Firebase Auth verification middleware
app.use(async (req, res, next) => {
  const idToken = req.headers.authorization?.split("Bearer ")[1];
  if (!idToken) return res.status(401).send("Unauthorized");
  try {
    const decoded = await getAuth().verifyIdToken(idToken);
    req.user = decoded;
    next();
  } catch (e) {
    res.status(401).send("Invalid token");
  }
});

app.post("/api/posts", async (req, res) => {
  const db = getFirestore();
  const ref = await db.collection(`tenants/${req.user.tenant_id}/posts`).add({
    title: req.body.title,
    authorId: req.user.uid,
    createdAt: new Date(),
  });
  res.json({ id: ref.id });
});

app.listen(process.env.PORT || 8080);

Step 3: Stripe Billing Integration

import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

// Create the Checkout Session
app.post("/api/checkout", async (req, res) => {
  const session = await stripe.checkout.sessions.create({
    mode: "subscription",
    customer_email: req.user.email,
    line_items: [{ price: "price_xxx", quantity: 1 }],
    success_url: "https://app.example.com/success",
    cancel_url: "https://app.example.com/cancel",
    client_reference_id: req.user.tenant_id,
  });
  res.json({ url: session.url });
});

// Receive the webhook
app.post("/webhooks/stripe", express.raw({ type: "application/json" }),
  async (req, res) => {
    const event = stripe.webhooks.constructEvent(
      req.body,
      req.headers["stripe-signature"]!,
      process.env.STRIPE_WEBHOOK_SECRET!
    );

    if (event.type === "checkout.session.completed") {
      const session = event.data.object;
      await getFirestore()
        .collection(`tenants/${session.client_reference_id}/subscriptions`)
        .doc("current")
        .set({ status: "active", stripeCustomerId: session.customer });
    }
    res.json({ received: true });
  }
);

Step 4: Cloud Scheduler Batch Jobs

# Cloud Scheduler -> start a Cloud Run Job
gcloud scheduler jobs create http daily-backup \
  --schedule="0 3 * * *" \
  --uri="https://my-api.run.app/jobs/backup" \
  --http-method=POST \
  --oidc-service-account-email=scheduler-sa@PROJECT.iam.gserviceaccount.com

Step 5: Firestore Backups

# Cloud Scheduler → Cloud Functions → Firestore Export
gcloud firestore export gs://my-backup-bucket/${TIMESTAMP} \
  --collection-ids=tenants

# Lifecycle rule: Archive after 90 days, delete after 365

Step 6: Monitoring and Alerting

  • Cloud Monitoring SLO: 99.9% availability + P95 < 500ms
  • Burn Rate Alert: fast burn (14.4x, 1h) → PagerDuty
  • Cloud Logging: structured logging (jsonPayload)
  • Error Reporting: automatic crash grouping
  • Uptime Check: HTTP probes from 5 global regions

Pricing Example (10K MAU per month)

ServiceMonthly cost
Cloud Run (~5M req/month)~$15
Firestore (~2M read + 500K write)~$5
Cloud Storage (10 GB)~$0.20
Firebase Auth (10K MAU)Free
Firebase Hosting~$0 (within free tier)
Cloud Logging (10 GB)Free
Cloud Scheduler (1 job)Free
Total~$20/month

Best Practices

  • Firebase Auth + Custom Claims (tenant_id / role)
  • Enforce tenant isolation with Firestore Security Rules
  • Min Instances 0 (accept cold starts to cut monthly cost)
  • Set Min Instances 1+ only on critical APIs
  • Manage API keys with Secret Manager
  • Use Workload Identity to eliminate service account keys
  • Make Stripe webhooks idempotent (dedupe by event.id)
  • Pre-define Firestore composite indexes

Can you build a SaaS on Cloud Run + Firestore?

Yes. With auto-scaling, fully managed services, a real-time database, and a generous free tier, you can run a SaaS serving thousands of users per month for just a few thousand yen.

What should I use for authentication?

Firebase Authentication (Google / Email / Apple / SAML, etc.) is the standard choice. You can also place IAP in front of Cloud Run for additional protection.

How should I design multi-tenancy?

Partition Firestore collections by tenant_id and enforce IAM via Security Rules. Cloud Run can stay as a single service with logical tenant isolation.

How far does it scale?

Cloud Run auto-scales to 1000 instances, Firestore handles 10K writes/s per collection, and Cloud Storage is unlimited. This stack typically handles SaaS workloads up to 100K MAU.

How do I handle subscription billing?

Stripe, Pay.jp, or Paddle are the standard options. Receive webhooks in Cloud Run and sync subscription state into Firestore.

How do I send transactional email?

SendGrid, Postmark, Resend, or Amazon SES are the standard SaaS options. Firebase Extensions also ships a SendGrid integration template.

What about backups?

For Firestore, run Managed Export daily via Cloud Scheduler and export to GCS. Point-in-time Recovery (7 days) is also enabled automatically.

How does this compare to Vercel / Netlify?

A modern setup is Vercel/Netlify for the frontend + Cloud Run for the backend + Firestore for the database. Firebase Hosting (with built-in CDN) is also a valid frontend choice.

Related articles: SaaS development

Cloud Scheduler + Functions for Batch Workflows (2026)

Scheduled batch with Cloud Scheduler and Functions — common ETL/maintenance patterns.

Professional Cloud Developer (PCD): Complete Guide (2026)

Pass the PCD exam — Cloud Run, GKE, App Engine, Cloud SQL/Spanner. The developer-focused Professional cert.

Cloud Deploy Complete Guide: GitOps for GKE (2026)

Cloud Deploy — delivery pipelines, targets, rollouts. The progressive delivery service for GKE.

Professional Cloud Network Engineer (PCNE): Guide (2026)

Pass the PCNE exam — VPC, Cloud Interconnect, Cloud VPN, Cloud Load Balancing, hybrid networking.

* Google Cloud and Firebase are trademarks of Google LLC. Stripe is a trademark of Stripe, Inc.

Check what you learned with practice questions

Practice with certification-focused question sets

View GCP exam prep
Author

NicheeLab Editorial Team

NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.


Related articles
Google Cloud

Google Cloud Certification Roadmap (2026)

Choose your GCP certification path — Foundational, Associate...

Google Cloud

CDL Cloud Digital Leader: Complete Exam Guide (2026)

Pass the Cloud Digital Leader exam — cloud business value, G...

Google Cloud

GAIL Generative AI Leader: Complete Exam Guide (2026)

Pass the Generative AI Leader exam — Gemini, Vertex AI, Work...

Google Cloud

Vertex AI Fundamentals for GCP Certs (2026)

Vertex AI basics every cert candidate needs — Workbench, Pip...

Google Cloud

Associate Cloud Engineer (ACE): Complete Guide (2026)

Pass the Associate Cloud Engineer exam — Console, gcloud, pr...

Browse all Google Cloud articles (103)
© 2026 NicheeLab All rights reserved.