Some SaaS architecture decisions are cheap to revisit and some are extremely expensive. Knowing which is which lets you move quickly on the reversible ones and think carefully about the rest.
Tenancy model is the expensive one. Shared database with a tenant column is simplest and most cost-efficient, and it is the right default for most products. Schema-per-tenant or database-per-tenant buys stronger isolation at a real operational cost. Choose based on the compliance requirements you actually have, not the ones you might.
Whichever model you choose, enforce tenant isolation in one place. A single data-access layer that always applies the tenant filter is far safer than relying on every query author to remember. Cross-tenant data leakage is the failure mode that ends SaaS companies.
Billing is harder than it appears. Plans, seats, usage metering, proration, upgrades mid-cycle, failed payments, and refunds interact in ways that produce genuinely tricky edge cases. Use a billing provider for the money movement and keep your own record of entitlements — what a customer is allowed to do should be answerable without an API call.
Design for the noisy neighbour from the beginning. One tenant running a heavy report should not degrade everyone else. Rate limiting per tenant, queue isolation for expensive jobs, and query timeouts prevent a single customer from becoming an incident.
Background jobs need the same rigour as request handling: idempotency, retry with backoff, dead-letter queues, and visibility into what failed. Most SaaS reliability problems trace back to a job system that fails silently.
Observability should be tenant-aware. When a customer reports slowness, being able to filter traces and logs by tenant turns an investigation from hours into minutes.
Onboarding and data export are product features with architectural consequences. Customers need to get in easily and, legally in many jurisdictions, get their data out. Building export later is considerably harder than designing for it early.