Multi-Tenant SaaS Architecture interview questions

32 questions from the Multi-Tenant SaaS Architecture course, each with the correct answer and an explanation. Try to answer before you open the answer.

The Multi-Tenant Mental Model

1. Which statement best describes multi-tenancy?

  1. Every customer gets a separately installed copy of the application
  2. One deployed system serves many customer organisations while keeping their data and settings isolated
  3. Multiple users can log in to the same account with one password
  4. The application runs in several cloud regions at the same time
Show answer

Answer: One deployed system serves many customer organisations while keeping their data and settings isolated

Multi-tenancy is about many customer organisations sharing one running system with logical isolation. Separate installs per customer is single-tenant hosting; multi-region is about availability, not tenancy.

Lesson: What Multi-Tenancy Means

2. In a B2B SaaS, which column should decide who owns an invoice row?

  1. The id of the user who created it
  2. The id of the user currently logged in
  3. The email domain of the creator
  4. The tenant_id of the organisation it belongs to
Show answer

Answer: The tenant_id of the organisation it belongs to

The organisation owns business data. Users come and go, and email domains are not reliable identifiers, so ownership and isolation are keyed on tenant_id.

Lesson: Tenants, Users and Memberships

3. Which of these is a control-plane responsibility?

  1. Rendering a tenant's dashboard page
  2. Provisioning resources for a newly signed-up tenant
  3. Serving a product search API call
  4. Running a tenant's scheduled report query
Show answer

Answer: Provisioning resources for a newly signed-up tenant

Onboarding and provisioning manage tenants as a whole, so they belong to the control plane. The other options are the product's day-to-day work in the application plane.

Lesson: Why SaaS Is Built This Way

Tenancy Models

4. A product runs shared API servers, but every customer has a dedicated PostgreSQL database. Which model is this?

  1. Pure pool
  2. Pure silo
  3. Bridge (hybrid)
  4. Single-tenant on-premises
Show answer

Answer: Bridge (hybrid)

Shared compute with dedicated databases mixes pooled and siloed layers, which is the bridge or hybrid model.

Lesson: Silo, Pool and Bridge Models

5. Why should the tenant-to-database mapping live in a catalogue rather than in application code?

  1. So tenants can be moved between tiers by changing data instead of redeploying code
  2. Because databases cannot be addressed by name from code
  3. So that every tenant must use the same database
  4. Because catalogues make SQL queries faster
Show answer

Answer: So tenants can be moved between tiers by changing data instead of redeploying code

A catalogue makes placement a data decision. Moving a tenant becomes migrate-then-update-catalogue, with no code change or redeploy.

Lesson: Tiering Tenants by Plan

6. A new B2B product expects thousands of small tenants and has a tiny ops team. What is the most sensible starting point?

  1. A dedicated cloud account per tenant
  2. A separate database server per tenant
  3. Separate code forks per large customer
  4. A pooled model with tenant_id on every row and a catalogue for future moves
Show answer

Answer: A pooled model with tenant_id on every row and a catalogue for future moves

Many small tenants and a small team favour pooling. Keeping tenant_id everywhere and a placement catalogue keeps the door open to silo specific tenants later.

Lesson: Choosing a Tenancy Model

Tenant Identity and Request Context

7. A request arrives for `acme.example-saas.com` with a valid token for a user who belongs only to the tenant `zen`. What should happen?

  1. Serve acme's data, since the hostname is valid
  2. Serve zen's data, since that is the user's tenant
  3. Silently redirect the user to a random tenant
  4. Reject the request, because the user has no membership in acme
Show answer

Answer: Reject the request, because the user has no membership in acme

The hostname names the requested tenant; the token proves which tenants the user may access. A mismatch must fail closed with an authorisation error.

Lesson: Resolving the Tenant for a Request

8. A web request enqueues a background job to generate a PDF. How should the worker know which tenant the job is for?

  1. The tenant_id is copied into the job message and the worker sets its context from it
  2. The worker inherits the web request's contextvars automatically
  3. The worker reads the tenant from the most recent HTTP request it saw
  4. The worker processes the job without tenant context
Show answer

Answer: The tenant_id is copied into the job message and the worker sets its context from it

In-process context does not travel through a queue. The producer must put tenant_id in the message and the consumer must restore context from it before touching data.

Lesson: Propagating Tenant Context

9. Why is a browser-supplied `X-Tenant-Id` header not enough to authorise access to a tenant?

  1. Headers are limited to 8 characters
  2. Browsers cannot send custom headers
  3. The client controls it, so it must be checked against verified memberships
  4. HTTP/2 drops custom headers
Show answer

Answer: The client controls it, so it must be checked against verified memberships

Anything the client sends can be forged. Only signed, verified claims or a server-side membership lookup can prove the user belongs to the tenant.

Lesson: Identity Tokens and Tenant Claims

Data Isolation Patterns

10. What is the main reason database-per-tenant becomes hard with very many small tenants?

  1. Databases cannot store more than one table
  2. Migrations, backups, monitoring and connections all multiply with the number of databases
  3. Cross-tenant data leaks become more likely
  4. SQL queries must include tenant_id in every WHERE clause
Show answer

Answer: Migrations, backups, monitoring and connections all multiply with the number of databases

Isolation is excellent, but operational work scales linearly with database count. Leaks are actually less likely, and tenant_id filters are not needed for isolation in this model.

Lesson: Database per Tenant

11. Why is `SET LOCAL search_path` preferred over `SET search_path` behind a connection pool?

  1. It runs faster
  2. It encrypts the schema name
  3. It reverts at transaction end, so the next request on that connection does not inherit the previous tenant's schema
  4. It is the only syntax PostgreSQL accepts
Show answer

Answer: It reverts at transaction end, so the next request on that connection does not inherit the previous tenant's schema

SET LOCAL lasts only until the transaction ends. A session-level SET survives on the pooled connection and can route a later request to the wrong tenant.

Lesson: Schema per Tenant

12. Why make the foreign key from tasks to projects `(tenant_id, project_id)` instead of just `project_id`?

  1. So that a task can only reference a project in the same tenant
  2. Because PostgreSQL forbids single-column foreign keys
  3. To make the tasks table smaller
  4. So that projects can be deleted without deleting tasks
Show answer

Answer: So that a task can only reference a project in the same tenant

With the composite key, the referenced project must have the same tenant_id as the task, so the database rejects cross-tenant links even if application code is buggy.

Lesson: Shared Tables with a tenant_id

Enforcing Isolation in Shared Databases

13. The app connects to PostgreSQL as the role that owns the `projects` table. RLS is enabled with a tenant policy, but FORCE was never run. What happens?

  1. Queries fail because owners cannot read their own tables
  2. Policies apply normally
  3. Only INSERT statements are filtered
  4. The policy is bypassed, so queries can see every tenant's rows
Show answer

Answer: The policy is bypassed, so queries can see every tenant's rows

Table owners bypass RLS unless FORCE ROW LEVEL SECURITY is set. Use a non-owner application role and FORCE as a belt-and-braces measure.

Lesson: Row-Level Security in PostgreSQL

14. A dashboard caches results under the key `stats:last30days`. What is the multi-tenant bug?

  1. The key lacks the tenant, so one tenant's cached stats can be served to another
  2. Cache keys may not contain colons
  3. Thirty days is too long to cache
  4. Caches cannot hold dashboard data
Show answer

Answer: The key lacks the tenant, so one tenant's cached stats can be served to another

Cache keys must include the tenant, for example `t:acme:stats:last30days`. Otherwise the first tenant to warm the cache decides what everyone sees.

Lesson: Scoping Every Data Access Path

15. Which test best guards against cross-tenant leaks in a new search endpoint?

  1. Check that search returns results within 200 ms
  2. Search as tenant A for a term that exists only in tenant B's data and assert zero results
  3. Search as an admin superuser and assert all results appear
  4. Check that the search endpoint returns valid JSON
Show answer

Answer: Search as tenant A for a term that exists only in tenant B's data and assert zero results

An isolation test seeds data in another tenant and proves it cannot be reached. Speed and JSON shape tests do not detect leaks, and superusers bypass the very rules you need to test.

Lesson: Testing Tenant Isolation

Scaling: Sharding and Noisy Neighbours

16. Why do many SaaS systems prefer a directory (lookup table) over pure `hash mod N` for tenant placement?

  1. Directories make every query cross-shard
  2. Hashing cannot handle string ids
  3. A directory lets you move or isolate individual tenants and add shards without reshuffling everyone
  4. Hashes are slower to compute than a database lookup
Show answer

Answer: A directory lets you move or isolate individual tenants and add shards without reshuffling everyone

With mod N, changing N remaps many tenants and you cannot pin a specific tenant. A directory makes placement an explicit, per-tenant, changeable fact.

Lesson: Sharding by Tenant

17. A shared job queue processes jobs in strict arrival order. Tenant A enqueues 50,000 jobs; tenant B then enqueues one. What change best protects tenant B?

  1. Increase the queue's maximum length
  2. Process jobs in reverse order
  3. Delete tenant A's jobs
  4. Schedule fairly across tenants, for example per-tenant queues served round-robin
Show answer

Answer: Schedule fairly across tenants, for example per-tenant queues served round-robin

Fair scheduling bounds how long one tenant waits behind another's backlog. A bigger queue or reverse order does not create fairness, and deleting jobs is not acceptable.

Lesson: Taming Noisy Neighbours

18. During an online tenant move, what is the purpose of the brief write freeze?

  1. To let replication drain so the target has every change before the directory flips
  2. To delete the old copy before copying
  3. To stop all tenants on the shard from writing
  4. To rebuild every index on the source shard
Show answer

Answer: To let replication drain so the target has every change before the directory flips

Freezing only that tenant's writes lets the last changes reach the target, so the flip loses nothing. Other tenants keep working, and deletion of the source comes last.

Lesson: Moving Tenants Between Shards

Tenant Lifecycle Operations

19. Why should each provisioning step be idempotent?

  1. So the workflow can be safely retried after a partial failure without duplicating resources
  2. So that steps run faster
  3. So tenants can skip email verification
  4. So that provisioning never needs a database
Show answer

Answer: So the workflow can be safely retried after a partial failure without duplicating resources

Failures halfway are normal. Idempotent steps mean a retry finishes the job instead of creating a second schema or a second admin invite.

Lesson: Onboarding and Provisioning

20. In expand-and-contract, when is the old column finally dropped?

  1. In the same migration that adds the new column
  2. Before deploying code that uses the new column
  3. After all running code has stopped reading and writing the old column
  4. Never; old columns must be kept forever
Show answer

Answer: After all running code has stopped reading and writing the old column

Contract happens last, once no deployed code depends on the old shape. Dropping earlier breaks the old code still running during a rolling deploy.

Lesson: Schema Migrations Across Many Tenants

21. Why do some SaaS platforms encrypt each tenant's data with its own key?

  1. It makes queries faster
  2. Destroying that key makes the tenant's data in old backups unreadable
  3. It removes the need for tenant_id columns
  4. It lets tenants read each other's data safely
Show answer

Answer: Destroying that key makes the tenant's data in old backups unreadable

Backups are hard to edit. Destroying a tenant-specific key (crypto-shredding) renders every remaining copy of that tenant's encrypted data useless.

Lesson: Offboarding, Export and Deletion

Plans, Customisation and Metering

22. Why is `if tenant.plan == 'pro':` in feature code a poor way to gate features?

  1. Python cannot compare strings
  2. Plans should never have names
  3. It ignores overrides and breaks when plans are renamed or added; a central entitlement check avoids both
  4. It is slower than a database query
Show answer

Answer: It ignores overrides and breaks when plans are renamed or added; a central entitlement check avoids both

Plan-name checks hard-code commercial packaging into product code. A central entitlement check handles overrides and new plans without hunting through the codebase.

Lesson: Plans and Entitlements

23. A large customer asks for a different approval workflow. Which approach keeps the product truly multi-tenant?

  1. Create a separate code branch for that customer
  2. Hard-code the customer's id with an if-statement
  3. Deploy a separate copy of the app just for them
  4. Add a configurable approval rule that any tenant can set
Show answer

Answer: Add a configurable approval rule that any tenant can set

Configuration keeps one codebase serving everyone. Forks, special-case ifs and separate deployments all multiply maintenance and drift.

Lesson: Per-Tenant Configuration and Customisation

24. A usage event for 120 API calls is delivered twice because of a network retry. What prevents the tenant being billed for 240?

  1. Deduplicating on the event's idempotency key
  2. Rounding usage down to the nearest hundred
  3. Billing only once per year
  4. Dropping all events that arrive within one second of each other
Show answer

Answer: Deduplicating on the event's idempotency key

Each logical event has a unique key, so a retried delivery is recognised and ignored. Time-based dropping would lose genuine events.

Lesson: Metering Usage for Billing

Security and Compliance per Tenant

25. A customer revokes the customer-managed key used for their tenant. What is the expected effect?

  1. Nothing changes until the next deployment
  2. The platform can no longer decrypt that tenant's data, so access to it fails
  3. All tenants on the same shard lose access
  4. The data is automatically re-encrypted with a platform key
Show answer

Answer: The platform can no longer decrypt that tenant's data, so access to it fails

Revoking the key-encryption key means wrapped data keys can no longer be unwrapped, so that tenant's data becomes unreadable. Other tenants use different keys and are unaffected.

Lesson: Per-Tenant Encryption Keys

26. A tenant is pinned to an India region. Which design choice most likely violates its residency requirement?

  1. Serving its API from the India cell
  2. Storing its backups in another India region
  3. Shipping its full request logs, including personal data, to a logging cluster in another continent
  4. Keeping only its tenant id and region in the global catalogue
Show answer

Answer: Shipping its full request logs, including personal data, to a logging cluster in another continent

Logs with personal data are regulated data. Sending them abroad breaks residency even if the primary database stays in India.

Lesson: Data Residency and Regional Deployments

27. Which practice best balances support needs with tenant trust?

  1. Time-limited, reason-required impersonation that is recorded in the tenant's audit log
  2. Giving support engineers the database superuser password
  3. Asking customers to share their passwords with support
  4. Letting support export any tenant's data without records
Show answer

Answer: Time-limited, reason-required impersonation that is recorded in the tenant's audit log

Controlled impersonation gives support what it needs while making access explicit, minimal and visible to the customer. The other options remove accountability.

Lesson: Audit Logs and Support Access

Observability and Cost per Tenant

28. Why is adding `tenant_id` as a label on every metric risky at large scale?

  1. Metric systems cannot store strings
  2. It creates a time series per tenant per label combination, which can explode storage and query cost
  3. It leaks data to other tenants
  4. Metrics are not allowed to have labels
Show answer

Answer: It creates a time series per tenant per label combination, which can explode storage and query cost

Cardinality multiplies with each label. With many tenants, per-tenant labels on every metric can overwhelm the metrics backend, so keep them on a chosen few.

Lesson: Tenant-Aware Observability

29. In the allocation example, acme uses about 87% of the CPU seconds but pays less than its allocated cost. What is the most reasonable first step?

  1. Delete acme's data to save cost
  2. Split the bill equally so the problem disappears
  3. Stop measuring CPU usage
  4. Investigate acme's heaviest workloads, then consider limits, a different plan or dedicated placement
Show answer

Answer: Investigate acme's heaviest workloads, then consider limits, a different plan or dedicated placement

Allocation exposes the imbalance; the response is to understand the workload first, fix inefficiencies, and then adjust pricing or placement. Equal splitting just hides the problem.

Lesson: Cost per Tenant and Unit Economics

Revision and Interview Prep

30. Which combination gives defence in depth for a pooled PostgreSQL database?

  1. Random UUIDs for ids and nothing else
  2. Scoped repositories, RLS enforced for a non-owner app role, and two-tenant isolation tests
  3. A tenant id header sent by the browser
  4. A superuser connection with careful code review
Show answer

Answer: Scoped repositories, RLS enforced for a non-owner app role, and two-tenant isolation tests

Each layer catches what the others miss: repositories make the safe path easy, RLS catches forgotten filters, tests prove it. Ids, client headers and superusers do not enforce isolation.

Lesson: Cheat Sheet: Multi-Tenancy on One Page

31. An interviewer asks: "Your pooled product just signed a bank that requires dedicated storage. What changes?" Which answer is strongest?

  1. Fork the codebase for the bank
  2. Refuse, because pooled products cannot host such customers
  3. Move every tenant to dedicated databases
  4. Provision a dedicated database for that tenant, record it in the catalogue, and keep the same application code routing by lookup
Show answer

Answer: Provision a dedicated database for that tenant, record it in the catalogue, and keep the same application code routing by lookup

Tier-based placement through a catalogue lets one tenant be siloed without a fork and without changing everyone else's placement.

Lesson: Common Interview and Exam Questions

32. In the snippet above, the connection comes from a pool and the table uses RLS keyed on `app.tenant_id`. What is the main problem?

  1. RLS cannot read custom settings
  2. SELECT statements are never filtered by RLS
  3. With is_local set to false the setting lasts for the whole session, so a later request on the pooled connection that forgets to set the tenant runs with this tenant's id
  4. Python cannot pass parameters to SQL
Show answer

Answer: With is_local set to false the setting lasts for the whole session, so a later request on the pooled connection that forgets to set the tenant runs with this tenant's id

set_config(..., false) behaves like a plain SET and lasts for the session. Run the work in a transaction with set_config(..., true) or SET LOCAL so the tenant setting cannot leak to the next borrower of the connection.

Lesson: Mixed Self-Check

← Back to the course