# A SaaS architecture on Cloud Run: tenants, sign-in, data, domains, and the bill as it grows

> A SaaS product on Cloud Run: one service and one database, a tenant id on every row under Postgres row security, sign-in, customer domains, and the bill at 5, 50 and 500 customers.

Published 2026-10-12 · Updated 2026-10-12 · [By Exodus team](https://exodus.elim.io/about) · New product, Patterns
<https://exodus.elim.io/blog/a-saas-architecture-on-cloud-run>

A SaaS architecture on Cloud Run is one service and one Postgres database for every tenant, with a tenant_id on every row under Postgres row security, Identity Platform for sign-in, and a load balancer with a wildcard certificate once customers want subdomains. At Google's list prices of October 12, 2026 in europe-west1 it costs about $10 a month at launch, $92 with 50 customers and $561 with 500.

## In short

- One Cloud Run service for every tenant: a service per tenant runs into the quota of 1,000 services per region and turns every release into hundreds of deploys.
- One Postgres database with a tenant_id on every row and row security, so a query that forgets its WHERE clause returns nothing; an instance per tenant starts at $9.37 a month.
- Identity Platform signs users in with email or a social account free up to 50,000 monthly active users; SAML and OIDC users, for customers with their own SSO, cost $0.015 each a month after the first 50.
- Subdomains need a load balancer at $18.25 a month and one wildcard certificate; certificates are free up to 100 per project, then $0.20 a month each.
- The database is the largest line of the bill at every stage: $9.37 of $9.89 at launch, $219.36 of $561.06 with 500 tenants.

![A diagram of the architecture: a browser signs in with Identity Platform, sends requests through a load balancer to one web and API service; the service reads Cloud SQL, gives signed URLs for Cloud Storage and puts tasks on Cloud Tasks, which calls a private worker service; Cloud Run jobs run migrations and nightly work](https://exodus.elim.io/media/v2026-09-16/t/exodus/assets/image-80dd69a8bc057eeedb083b12ac54cd57aa3c80c177e228c1774d5761a8ab4895-680x420-svg/bytes "The parts. Dashed boxes are added when the product needs them, not on day one.")

## What a tenant is in the code

A SaaS product sells the same app to many customers, and each customer is a tenant: the unit a customer pays for, a company account, a workspace, a team. The basics are in [what Cloud Run is](https://exodus.elim.io/blog/what-cloud-run-is) and [planning a new product for Cloud Run](https://exodus.elim.io/blog/planning-a-new-product-for-cloud-run). Users belong to tenants, sometimes to several, with a role in each. Everything a tenant owns carries the tenant's id.

The rule that keeps a SaaS safe: the server decides the tenant, never the request. A request may say which tenant the user wants, through a subdomain, a path or a header, but the server checks that the signed-in user is a member of that tenant before it reads a row. Every request goes through three steps, in one place in the code:

1. Verify the ID token (the signed proof of sign-in, as in [IAM for a Cloud Run app](https://exodus.elim.io/blog/iam-for-a-cloud-run-app)) and take the user's id from it.
1. Work out the tenant the request is for, and look up the user's membership and role in it.
1. Open a database transaction with the tenant's id set (below), and run the handler inside it.

## Sign-in: Identity Platform, with or without tenants

Identity Platform is Google Cloud's sign-in service, used through the Firebase client and Admin SDKs. The browser signs the user in and gets an ID token; the API verifies the token and never sees a password.

Most SaaS products need one user pool and a memberships table: a person signs up once and can be invited to several tenants. Identity Platform also has its own **tenants**, separate silos of users and configuration inside one project, which Google describes as most often used in business-to-business apps. Each has its own users, identity providers, quota and usage breakdown. Use them when a customer wants its staff to sign in through its own SAML or OIDC provider, or when a customer's users must not exist in anyone else's pool. What changes with them:

- The browser sets the tenant before sign-in (`auth.tenantId = "..."` in the web SDK), so the sign-in page must know the tenant first, from a subdomain or a "your company" field.
- The API verifies the token for that tenant, with `authForTenant(tenantId)` and then `verifyIdToken(token)` in the Node.js Admin SDK, and the same calls in Java, Python, Go and C#. A token from another tenant fails with `auth/mismatching-tenant-id`.
- Authorized domains and redirect URIs are inherited from the parent project. Tenants cannot disable account linking or have a blocking function of their own.
- Without a billing account a project gets 2 tenants; with one, any number.

The price follows the provider that signed the user in. Tier 1, email and password, phone, anonymous and social, is free up to 50,000 monthly active users, then $0.0055 a user, falling to $0.0025 above 10 million. Tier 2, SAML and OIDC, is free for 50 users, then $0.015 a user. A user is active in a month if they signed in during it; stored users who did not cost nothing. A customer who brings 300 staff through their own SSO adds up to $4.50 a month, which belongs in the price of the plan that includes SSO.

## Where the tenant's data lives

There are four ways to separate tenants in a database. Google's comparison for Spanner holds for Postgres too: the more a pattern isolates, the more each tenant costs and the harder changes become.

![A table of four tenancy models: shared tables with a tenant_id column, isolated by a row policy, a new tenant is one INSERT and migrations run once; a schema per tenant; a database per tenant; and a Cloud SQL instance per tenant at $9.37 a month or more, where migrations run once per tenant](https://exodus.elim.io/media/v2026-09-16/t/exodus/assets/image-2b4565f60e1ff586071e91a5b1cad6037946ef7459bd6587069b21181a90e5bb-680x340-svg/bytes "Four places a tenant can live. The first fits most products; the last is a price a customer pays for.")

- **Shared tables.** Every table has a `tenant_id` column. A new tenant is one row, a migration runs once, and the database grows with the data, not the number of tenants. The risk is a query that forgets the tenant; row security closes it.
- **A schema or a database per tenant.** Better isolation, but every migration runs once per tenant, and a database per tenant needs a connection pool per tenant, which a small instance cannot afford ([connection pooling](https://exodus.elim.io/blog/connection-pooling-on-cloud-run) explains why).
- **An instance per tenant.** Complete isolation, from $9.37 a month per tenant with the smallest Cloud SQL instance and 10 GiB of disk. A customer who asks for it pays for it. Google's App Lifecycle Manager (formerly SaaS Runtime, Public Preview) manages Terraform deployments per tenant for it.

Start with shared tables. A tenant who later needs its own instance can be moved out, because its rows are already labelled.

## Row security, step by step

Postgres row security adds a condition to every query on a table, whatever the app's SQL says. The app sets the tenant at the start of each transaction, and a policy compares each row's `tenant_id` with that setting.

It needs two database roles. The **migration role** owns the tables and runs migrations. The **app role**, the one the Cloud Run service connects as, owns nothing and is granted `SELECT, INSERT, UPDATE, DELETE`. The split matters because a table's owner, every superuser and any role with `BYPASSRLS` skip row security. The migration that switches it on:

```
ALTER TABLE projects ENABLE ROW LEVEL SECURITY;
ALTER TABLE projects FORCE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON projects
  USING (tenant_id = nullif(current_setting('app.tenant_id', true), '')::bigint)
  WITH CHECK (tenant_id = nullif(current_setting('app.tenant_id', true), '')::bigint);
```

`USING` filters the rows a query can see or change; `WITH CHECK` refuses a new or updated row for another tenant. `current_setting(..., true)` returns nothing instead of an error when the setting is missing, so a query with no tenant sees no rows, and `nullif` does the same for the empty string Postgres returns once a transaction-local setting has ended. Each request then runs in a transaction that starts like this:

```
BEGIN;
SELECT set_config('app.tenant_id', '42', true);
-- the handler's queries
COMMIT;
```

The third argument, `true`, makes the setting last until the end of the transaction. That matters because the service keeps a pool of connections, and the next request on a connection may belong to another tenant. A session-level setting (`false`, or a plain `SET`) stays on the connection, and a request that forgets to set its own tenant runs as the previous one. We ran all of this on a local Postgres 17; the picture is what the script printed.

![Terminal output of the row security test: without a policy the app role sees rows of tenants 1 and 2; with the policy and no tenant set it sees 0 rows; with tenant 1 set it sees two rows and an insert for tenant 2 fails with "new row violates row-level security policy"; the owner sees 3 rows until FORCE and 0 after; a session-level setting leaks 1 row to the next query, a transaction-local one leaks none](https://exodus.elim.io/media/v2026-09-16/t/exodus/assets/image-8184923b22ff50e0ee06abbf1b44dbfbd5248076722d45c670c7ad797b97f884-680x436-svg/bytes "Our local test. Section 3 is the owner trap, section 4 the pooled connection trap.")

Three details from the Postgres documentation. With row security on and no policy, nothing is visible, so a forgotten policy fails closed. Unique and foreign key checks bypass row security: if `projects.slug` is unique across the table, a tenant learns that another tenant used a slug from the duplicate key error, so make it `UNIQUE (tenant_id, slug)`. And backups should run with `row_security = off`, which makes a query fail instead of silently skipping rows. Row security is the second lock: the handler still filters by tenant, which also lets Postgres use indexes that start with `tenant_id`.

## Files, background work and schedules

**Files** go to one Cloud Storage bucket with a prefix per tenant, `t/42/invoices/2026-10.pdf`. The API checks the membership, then issues a signed URL for one object for a few minutes ([files and uploads](https://exodus.elim.io/blog/files-and-uploads-with-cloud-storage)). Standard storage in europe-west1 costs $0.02 per GiB a month.

**Background work** goes to Cloud Tasks. The task carries the tenant id, and the worker sets it in its transaction as the API does; a worker that skips that step sees no rows, so the mistake shows at once. One customer's large import can fill a queue and delay everyone's emails, so cap a queue with `--max-concurrent-dispatches` and give heavy work its own queue. The first million operations a month are free, then $0.40 per million ([background workers](https://exodus.elim.io/blog/background-workers-with-cloud-tasks)).

**Schedules** do not get a Cloud Scheduler job per tenant. A job costs $0.10 a month after the first 3 per billing account, so 500 tenants with a nightly report each would cost $50 a month in schedules. One job starts a Cloud Run job each night, which puts one task per tenant on a queue ([cron and timers](https://exodus.elim.io/blog/cron-and-timers-with-cloud-scheduler)).

## Services, identities and environments

Cloud Run allows 1,000 services per project and region. Split services by job, not by tenant: the web app and API, a private worker that only Cloud Tasks calls, perhaps a public API for customers' integrations. Payments arrive as webhooks on the web service and go on to the worker, as in [Stripe webhooks on Cloud Run](https://exodus.elim.io/blog/stripe-webhooks-on-cloud-run); an assistant inside the product follows [an AI agent backend on Cloud Run](https://exodus.elim.io/blog/an-ai-agent-backend-on-cloud-run), with the membership check from here on every session. Each gets its own service account with only the roles it needs, because a service without one runs as the Compute Engine default service account, which Google recommends against. In our own project, eight services run with eight service accounts ([IAM for a Cloud Run app](https://exodus.elim.io/blog/iam-for-a-cloud-run-app)).

```shell
gcloud run deploy app \
  --region europe-west1 \
  --image europe-west1-docker.pkg.dev/my-saas-prod/app/app:v42 \
  --service-account app-runtime@my-saas-prod.iam.gserviceaccount.com \
  --set-cloudsql-instances my-saas-prod:europe-west1:main
```

Run staging and production in two projects, `my-saas-staging` and `my-saas-prod`, and promote the same image. A project is the boundary of IAM, quotas and the bill, so a test in staging cannot touch a customer's data ([setting up a project](https://exodus.elim.io/blog/setting-up-a-google-cloud-project-for-a-small-team)).

## Domains: one hostname, a subdomain each, then theirs

![Three columns: one hostname, app.example.com, through Firebase Hosting or a domain mapping, with no load balancer and the tenant taken from the sign-in; a subdomain each, t42.example.com, through a load balancer with one wildcard certificate, $18.25 a month for the forwarding rule; the customer's own domain, app.example.net, a CNAME to your address and a certificate map entry each, $0.20 a month per certificate after 100](https://exodus.elim.io/media/v2026-09-16/t/exodus/assets/image-bea8c6dbaaa6d1d0b58fea9daaf7ba600d8e6d04e93a0942f9122a746f66f7e9-680x330-svg/bytes "Three steps for hostnames. Most products start at the first and move when customers ask.")

**At launch, one hostname** for everyone, `app.example.com`, with the tenant taken from the user's memberships and a switcher in the UI. Cloud Run's domain mapping is the simplest option, but Google marks it Preview, says it is not production-ready because of latency issues, and offers it in 10 regions. Firebase Hosting in front of the service, or a load balancer, are the production options ([custom domains and HTTPS](https://exodus.elim.io/blog/custom-domains-and-https-on-cloud-run)).

**A subdomain per tenant**, `t42.example.com`, needs a wildcard certificate, one certificate valid for every name under `example.com`. That needs a load balancer, Google's managed front door with its own IP address that ends HTTPS and forwards requests to your service: the global external Application Load Balancer, with Certificate Manager issuing the certificate. A certificate authorized by the load balancer cannot be a wildcard; one with a DNS authorization can, and covers one level: `*.example.com` covers `t42.example.com`, not `a.t42.example.com`.

```shell
gcloud certificate-manager dns-authorizations create saas-dns \
  --domain=example.com
# the CNAME record to add to your DNS:
gcloud certificate-manager dns-authorizations describe saas-dns
gcloud certificate-manager certificates create saas-wildcard \
  --domains="example.com,*.example.com" \
  --dns-authorizations=saas-dns
gcloud certificate-manager maps create saas-map
gcloud certificate-manager maps entries create saas-wildcard-entry \
  --map=saas-map \
  --certificates=saas-wildcard \
  --hostname="*.example.com"
```

The load balancer's HTTPS proxy takes the map with `--certificate-map=saas-map`, and its backend is a serverless network endpoint group, the object that points a load balancer at a Cloud Run service; the custom domains guide has the full sequence. Then deploy the service with `--ingress internal-and-cloud-load-balancing`, so its `run.app` address stops answering from the internet. The forwarding rule costs $0.025 an hour, $18.25 a month, plus $0.008 per GiB processed in each direction.

**A customer's own domain**, `app.example.net`: the customer adds a CNAME from their name to yours, and you create a certificate and a map entry for their hostname. With load balancer authorization the certificate can be provisioned only once the load balancer serves that name, so it is issued after their CNAME points at you and the first minutes may fail; a DNS authorization lets it be issued in advance, for one more CNAME on their side. The app maps the `Host` header to a tenant and still checks membership. The limits: 1,000 Google-managed certificates per project by default, 5 domains per certificate with load balancer authorization and 100 with DNS authorization, 4 certificates per map entry. Certificates cost nothing up to 100 a project, then $0.20 each a month. At 1,000 customer domains that is about $180 a month, and the quota needs raising before the next one.

## What it costs as it grows

The same product at three sizes, in europe-west1 at Google's list prices of October 12, 2026, from the pricing pages and the Cloud Billing Catalog API. Each request takes 0.2 seconds of 1 vCPU and 512 MiB, counted as if no two requests overlapped, so the Cloud Run lines are an upper bound; with concurrency an instance serves several requests at once and bills less.

![A bar chart of the monthly bill: $9.89 at launch with 5 tenants and 300 users, $91.87 with 50 tenants and 3,000 users, $561.06 with 500 tenants and 60,000 users; the Cloud SQL part, shown darker, is most of the first bar and about 40 percent of the last](https://exodus.elim.io/media/v2026-09-16/t/exodus/assets/image-baf12782d436fda15d0ed7fa454ca6dbdefe3a13bc1eed3ff1fc7a1467524bb1-680x380-svg/bytes "The same product at three sizes. The database leads at every stage.")

- **Launch: 5 tenants, 300 users, 300,000 requests a month, about $9.89.** Cloud Run stays in its free tier (60,000 vCPU-seconds of 180,000). Cloud SQL's db-f1-micro is $7.67 for 730 hours plus $1.70 for 10 GiB of SSD. Storage is $0.04 and 5 GiB of traffic out $0.48; sign-in, tasks, two schedules and three secrets are free. The database is 95% of the bill. The shared-core instance is outside Cloud SQL's SLA, acceptable before anyone pays ([Cloud SQL's smallest instances](https://exodus.elim.io/blog/cloud-sql-smallest-instances-and-what-they-cost)).
- **First customers: 50 tenants, 3,000 users, 3 million requests, about $91.87.** Cloud Run: 420,000 vCPU-seconds over the free tier, $10.08, plus $0.40 for requests. Cloud SQL on a dedicated core for the SLA, 1 vCPU and 3.75 GB with 20 GiB: $52.71. The load balancer for subdomains: $18.73. Two customers on SAML with 200 users: $2.25. Traffic out, 60 GiB: $7.08. Storage, secrets and a fourth schedule: $0.62.
- **Growing: 500 tenants, 60,000 users, 30 million requests, about $561.06.** Cloud Run: $157.48. Cloud SQL with 2 vCPU, 8 GB and high availability, which doubles the price, and 50 GiB: $219.36. Sign-in: 9,000 users over the free 50,000 at $0.0055 and 1,000 SSO users, $63.75. 201 certificates, 101 of them paid: $20.20. The load balancer with 600 GiB: $23.05. Traffic out: $71.88. The rest: $5.34. That is $1.12 a tenant.

The database leads at every stage, so size it from measured load ([backups and point-in-time recovery](https://exodus.elim.io/blog/backups-and-point-in-time-recovery-on-cloud-sql) is the other half of running it). SSO and custom domains have a price per customer, so they belong on the plans that pay for them. Traffic out grows with every customer ([egress on Google Cloud](https://exodus.elim.io/blog/egress-on-google-cloud-explained)).

## What breaks

- **A tenant id from the URL, trusted.** The hostname or path says which tenant the user wants; only a membership check says they may.
- **The app connects as the table owner.** Row security does nothing for the owner without `FORCE ROW LEVEL SECURITY`, and nothing for a superuser or a `BYPASSRLS` role.
- **A session-level setting on a pooled connection.** The next request on that connection runs as the previous tenant. Set the tenant per transaction; behind a pooler such as PgBouncer in transaction mode, nothing session-level at all.
- **A unique constraint across all tenants.** It leaks whether a name exists elsewhere and stops two tenants from using the same name.
- **A Scheduler job per tenant, or one queue for everything.** The first costs $0.10 a month per customer; the second lets one customer's import delay everyone.
- **A service per tenant.** It reaches the services quota, multiplies deploy time and cold starts.
- **A customer domain with load balancer authorization and no warning.** The certificate comes after their DNS points at you; tell them, or use a DNS authorization.
- **Identity Platform tenants for every customer by default.** Then one person cannot belong to two customers with one login.

## Checklist

1. One image and one service for the web app and API; a private worker for tasks; jobs for migrations and nightly work.
1. A service account per service; staging and production in separate projects.
1. `tenant_id` on every tenant-owned table, first in large indexes and in unique constraints.
1. Row security enabled and forced, a migration role that owns the tables and an app role that does not.
1. Every request and task in a transaction that starts with `set_config('app.tenant_id', ..., true)`, after a membership check.
1. Files under a per-tenant prefix, handed out through short signed URLs.
1. Identity Platform tenants only for customers with their own SSO, priced into that plan.
1. A load balancer and a wildcard certificate for subdomains; a certificate per customer domain; ingress closed to all but the load balancer.
1. A budget alert before the first customer ([budget alerts](https://exodus.elim.io/blog/budget-alerts-and-the-billing-export)).

## Where Exodus comes in

Exodus does not design tenancy. For an app you already run, `exodus audit` lists its processes, data stores and the patterns that break on Cloud Run, and asks which domains point at the app, which outside services it calls and which environments it runs in. On a copy of one of the CLI's sample apps it found the web process, a worker, timers, Postgres, Redis and local files, and `exodus report` mapped them to Cloud Run, Cloud Tasks, Cloud Scheduler, Cloud SQL and Cloud Storage. It does not look for a tenant id or row security, and its estimate has no line for Identity Platform, certificates or a load balancer. Those are decisions for you and your coding agent, which can read this guide through `exodus kb` and `exodus ask`.

## FAQ

### Should each tenant get its own Cloud Run service?

No. One image and one service serve every tenant, and the server decides the tenant from a membership check. Cloud Run allows 1,000 services per project and region, so a service per tenant runs into that quota and turns every release into hundreds of deploys, with more cold starts.

### How do I stop one tenant from reading another tenant's rows in Postgres?

Put a tenant id on every row, enable and force Postgres row security with a policy that compares it with a setting made per transaction, and connect the app as a role that does not own the tables. Superusers, roles with BYPASSRLS and owners without FORCE skip row security.

### How much does Identity Platform cost for a SaaS product?

Email, phone, anonymous and social sign-in are free up to 50,000 monthly active users, then $0.0055 a user, falling to $0.0025 above 10 million. SAML and OIDC are free for 50 users, then $0.015 a user. A customer who brings 300 staff through their own SSO adds up to $4.50 a month.

### How do customers bring their own domain to a Cloud Run app?

The customer adds a CNAME from their hostname to yours, and you create a Certificate Manager certificate and a map entry for it on a global external Application Load Balancer, which costs $18.25 a month. Certificates are free up to 100 per project, then $0.20 each a month, with a default quota of 1,000.

### Is Cloud Run domain mapping ready for production?

No. Google marks Cloud Run domain mapping as Preview, says it is not production-ready because of latency issues, and offers it in 10 regions. Firebase Hosting in front of the service, or a global external Application Load Balancer, are the production options for a custom domain.

## Sources

1. [Identity Platform multi-tenancy, Google (tenants are silos of users and configuration in one project, most often used in B2B apps; each tenant has its own users, identity providers, auditing and IAM configuration, quota and usage breakdown; email and password, social, SAML and OIDC supported; tenants do not support disabling account linking or a tenant-specific blocking function; updated Oct 9, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/identity-platform/docs/multi-tenancy)
2. [Managing Identity Platform tenants programmatically, Google (tenant-aware Admin SDK in Node.js, Java, Python, Go and C#; authForTenant and verifyIdToken for a tenant; auth/mismatching-tenant-id when a user's tenant does not match; authorized domains and redirect URIs are inherited from the parent project; custom claims per tenant; updated Sep 24, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/identity-platform/docs/multi-tenancy-managing-tenants)
3. [Identity Platform quotas and limits, Google (2 tenants per project without a billing account, unlimited with one; no limit on identity providers per project or tenant; read Oct 12, 2026)](https://docs.cloud.google.com/identity-platform/quotas)
4. [Identity Platform pricing, Google, and its SKUs in the Cloud Billing Catalog API (Tier 1, email, phone, anonymous and social: 50,000 monthly active users free, then $0.0055, $0.0046 from 100,000, $0.0032 from 1 million, $0.0025 from 10 million; Tier 2, SAML and OIDC: 50 free, then $0.015; the tier follows the identity provider that authenticated the user; read Oct 12, 2026)](https://cloud.google.com/identity-platform/pricing)
5. [Cloud Run quotas and limits, Google (1,000 services, 1,000 jobs and 1,000 worker pools per project and region, can be increased; 100 instances per project and region by default, can be increased; 1,000 revisions kept per service; updated Oct 9, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/run/quotas)
6. [Introduction to service identity, Cloud Run, Google (a user-managed service account with the minimal permissions is recommended; the Compute Engine default service account is used when none is set; updated Oct 7, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/run/docs/securing/service-identity)
7. [Map custom domains, Cloud Run, Google (a global external Application Load Balancer, Firebase Hosting, or Cloud Run domain mapping, which is Preview, not production-ready and not recommended for production services, in 10 regions, 64 characters at most, no self-managed certificates; a mapping's certificate usually takes about 15 minutes, up to 24 hours; updated Oct 7, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/run/docs/mapping-custom-domains)
8. [Domain authorization types for Google-managed certificates, Certificate Manager, Google (load balancer authorization needs no DNS record but supports no wildcard and provisions only after the load balancer is set up and serving traffic; a DNS authorization can provision in advance and covers a domain and its wildcard, first level only; updated Oct 9, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/certificate-manager/docs/domain-authorization)
9. [Deploy a global Google-managed certificate with DNS authorization, Certificate Manager, Google (dns-authorizations create, certificates create with --dns-authorizations, maps create, maps entries create with --hostname; updated Oct 9, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/certificate-manager/docs/deploy-google-managed-dns-auth)
10. [Certificate Manager quotas and limits, Google (1,000 Google-managed certificates per project by default; 5 domains per certificate with load balancer authorization, 100 with DNS authorization; 4 certificates per map entry; updated Aug 11, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/certificate-manager/docs/quotas)
11. [Certificate Manager pricing, Google, and its SKUs in the Cloud Billing Catalog API (100 certificates a month free per project, then $0.20 a certificate a month, $0.10 from 2,000; no per-connection charge for RSA-2048 and ECDSA keys; read Oct 12, 2026)](https://cloud.google.com/certificate-manager/pricing)
12. [Cloud Load Balancing pricing, Google (global forwarding rules: first 5 $0.025 an hour, each further $0.01; inbound and outbound data processed $0.008 per GiB; read Oct 12, 2026)](https://cloud.google.com/load-balancing/pricing)
13. [Network pricing, Google (Premium Tier internet data transfer to Europe: first GiB free, then $0.12 per GiB to 1 TiB; read Oct 12, 2026)](https://cloud.google.com/vpc/network-pricing)
14. [Cloud Run pricing, Google (request-based services in Tier 1 regions: $0.000024 per vCPU-second, $0.0000025 per GiB-second, $0.40 per million requests; free each month 180,000 vCPU-seconds, 360,000 GiB-seconds and 2 million requests; internet egress at networking prices; no charge for transfer to Google Cloud resources in the same region; read Oct 12, 2026)](https://cloud.google.com/run/pricing)
15. [Cloud SQL pricing, Google, and Cloud SQL for PostgreSQL SKUs for europe-west1 in the Cloud Billing Catalog API (db-f1-micro $0.0105 an hour; Enterprise zonal $0.0413 per vCPU-hour and $0.007 per GiB-hour, regional (high availability) $0.0826 and $0.014; SSD $0.17 per GiB-month zonal, $0.34 regional; shared-core types not covered by the SLA; read Oct 12, 2026)](https://cloud.google.com/sql/pricing)
16. [Cloud Billing Catalog API, Cloud Storage SKUs (Standard Storage in Belgium, europe-west1, $0.02 per GiB-month; read Oct 12, 2026)](https://cloud.google.com/storage/pricing)
17. [Cloud Tasks quotas and limits, Google (1,000 queues per region; a queue dispatches at most 500 tasks a second, use more queues for more; updated Oct 9, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/tasks/docs/quotas)
18. [Configure queue routing, limits, and retries, Cloud Tasks, Google (gcloud tasks queues update with --max-dispatches-per-second and --max-concurrent-dispatches; updated Oct 9, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/tasks/docs/configuring-queues)
19. [Cloud Tasks pricing, Google (first 1 million operations a month free, then $0.40 per million; read Oct 12, 2026)](https://cloud.google.com/tasks/pricing)
20. [Cloud Scheduler pricing, Google ($0.10 a job per 31 days; 3 jobs free per billing account; read Oct 12, 2026)](https://cloud.google.com/scheduler/pricing)
21. [Secret Manager pricing, Google (6 active secret versions free, then $0.000082192 an hour, $0.06 a month, each; read Oct 12, 2026)](https://cloud.google.com/secret-manager/pricing)
22. [Implement multi-tenancy in Spanner, Google (instance, database, table and row patterns; data isolation complete, high, moderate, low; agility low to highest; updated Oct 7, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/spanner/docs/implement-multi-tenancy)
23. [App Lifecycle Manager overview, Google (formerly SaaS Runtime; manages Terraform deployments of a SaaS application across tenants, with rollouts in batches; the product page marks it Public Preview; updated Aug 11, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/app-lifecycle-manager/overview)
24. [Create projects, Resource Manager, Google (tags to mark a project as production, staging, development or test; updated Oct 6, 2026, read Oct 12, 2026)](https://docs.cloud.google.com/resource-manager/docs/creating-managing-projects)
25. [Row Security Policies, PostgreSQL documentation (default deny when no policy exists; superusers and BYPASSRLS roles always bypass; table owners normally bypass unless FORCE ROW LEVEL SECURITY; unique and foreign key checks bypass row security; read Oct 12, 2026)](https://www.postgresql.org/docs/current/ddl-rowsecurity.html)
26. [CREATE POLICY, PostgreSQL documentation (USING for existing rows, WITH CHECK for new ones; read Oct 12, 2026)](https://www.postgresql.org/docs/current/sql-createpolicy.html)
27. [System administration functions, PostgreSQL documentation (current_setting with missing_ok returns NULL; set_config with is_local true lasts for the current transaction; read Oct 12, 2026)](https://www.postgresql.org/docs/current/functions-admin.html)
28. [gcloud certificate-manager, gcloud compute network-endpoint-groups create, gcloud compute target-https-proxies create, gcloud run deploy, Google Cloud SDK (--domains with --dns-authorizations, --hostname, --network-endpoint-type=serverless with --cloud-run-service, --certificate-map, --ingress internal-and-cloud-load-balancing, --service-account; location defaults to global; checked against gcloud 587.0.0 help on Oct 12, 2026)](https://docs.cloud.google.com/sdk/gcloud/reference/certificate-manager)
29. Exodus team: on Oct 12, 2026 we ran a row security test on a local Postgres 17 (a migration role owning the tables, an app role without it: no rows with no tenant set, only the tenant's rows inside a transaction, an INSERT for another tenant refused, the owner seeing every row until FORCE, a session-level setting leaking to the next query on the same connection, a transaction-local one not); read our own project's eight Cloud Run services, each with its own service account; and ran exodus 0.1.1 on a sample app
