Forge64 logo
All app types

SaaS dashboard scaling

SaaS dashboard scaling and launch checklist

A SaaS dashboard stays fast by paginating every list, indexing the main questions, and deferring heavy work until a measured trigger fires. At launch, apply 9 rules, watch 6 signals and hold the performance targets below.

Last checked

Rules to apply at launch

  • Data growth: Every org-owned table has org_id as the leading column of its hot index and an RLS policy; no query is allowed without an org scope, so a single large tenant cannot degrade scans for others.
  • Pagination: Every list (members, audit log, deliveries, API data) uses keyset pagination on an indexed (sort_key, id) tuple with a cursor token; no OFFSET; page size defaults to 25 and is capped at 100.
  • Caching: Dashboards read pre-aggregated metrics_daily and usage_rollups, never count(*) over raw tables; every chart is a single range query bounded to <= 366 points.
  • Caching: Public pages (/pricing, docs) are statically rendered with edge caching; authenticated pages send Cache-Control: private, no-store and use server-side per-org caches (Next.js cache tags) invalidated on writes, TTL <= 60 s.
  • Rate limits: Per-API-key and per-org token-bucket limits (plan-based requests per minute and per day) stored in a Postgres rate_limits table with atomic UPDATE ... RETURNING; auth endpoints are limited per IP and per account; limit hit returns 429 with Retry-After.
  • Fanout: Usage events are buffered in process and flushed in one multi-row INSERT every 5 s or 500 rows, so metering adds <= 1 write per flush per worker, not one per API call.
  • Search: In-app search over members, audit entries and resources uses tsvector + GIN or pg_trgm scoped by org_id; a dedicated search service is deferred.
  • Storage: Org uploads (logos, exports, attachments) go via presigned PUT to object storage under `org/<org_id>/` with per-plan byte quotas checked before the URL is issued.
  • Realtime: Live dashboard widgets use polling with ETag/If-None-Match every 15-30 s or an SSE stream fed by LISTEN/NOTIFY; a dedicated websocket tier is deferred.

Performance targets

Performance targets for a SaaS dashboard
What to measureTarget
Dashboard page (authenticated) TTFBp95 < 400 ms with <= 12 queries, every chart one indexed read
Public API requestp95 < 150 ms for reads, p99 < 400 ms for writes, <= 5 queries
Usage ingestp99 < 100 ms per batch, one INSERT per batch
Limit check (assertWithinLimit)p99 < 10 ms, one primary-key read
Webhook delivery latencyp95 < 30 s from event to first attempt
Audit log pagep95 < 300 ms at 10M rows per org via keyset index

What to watch

  • Metric api request duration ms: histogram by route, status class and plan; powers the latency SLO.
  • Metric usage events flush lag s: age of the oldest unflushed usage buffer and rollup lag.
  • Metric webhook delivery success ratio: per endpoint and global; consecutive-failure counter drives auto-disable.
  • Log structured request and audit logs: request id, org id, actor id hash, route, permission decision; no tokens, keys or email addresses.
  • Trace request to webhook delivery trace: one trace id from the domain event to the signed POST.
  • Slo api availability: 99.9% of authenticated API requests succeed; error budget reviewed monthly.

Recurring work

  • rollup_usage: runs cron 1m. Guard: bounded batch by id range, upsert by (org_id, meter, period_start), advisory lock so two runs never overlap.
  • deliver_webhook: runs queue (webhook_deliveries). Guard: SSRF re-check, 10 s timeout, attempt cap 8, response body truncated to 2 KB, per-endpoint concurrency 1.
  • build_metrics_daily: runs cron hourly + nightly backfill. Guard: recompute only today and yesterday hourly; idempotent upsert; bounded per-org work.
  • export_audit_csv: runs queue (jobs kind=export_audit). Guard: streams to object storage in chunks, max rows and bytes per export, one running export per org, signed link expires in 24 h.
  • sweep_trial_and_dunning: runs cron daily. Guard: reads subscriptions by (status, current_period_end) in batches; sends at most one reminder per stage per org.

Add when the numbers say so

  • Read replicas: Route dashboard, audit and export reads to a read replica once primary CPU or read p95 crosses the trigger; reads and writes already use separate repository functions so this is configuration.
  • Fanout: Move outbound webhook fan-out and usage ingest to a dedicated event bus once sustained ingest exceeds what one Postgres queue handles.

Deferred until it is needed

Work to defer for a SaaS dashboard, with the trigger for adopting it
DeferredAdopt it when
Custom roles and fine-grained permissions3+ customers ask for custom roles.
Dedicated event bus for webhooks and ingestsustained ingest > 2k events/s or queue claim p95 > 100 ms.
Read replicas for dashboards and auditprimary CPU > 60% sustained or dashboard read p95 > 300 ms.
Columnar analytics storead-hoc customer analytics scans > 100M rows per query.

On Forge64

Forge64 matches your description to one of 12 reference architectures, writes the plan and data model into the project, generates the app, and runs a quality gate over the code before you see it. Each app gets its own Postgres database and sign-in with no per-user fee. Hosting on Forge Cloud and Forge Payments are rolling out.

Every metered resource on Forge64 has a hard cap, so a traffic spike stops at your limit instead of becoming a surprise bill. This is a reference design for the category, not a promise that every item is generated today. Built-ins such as email, background jobs, file uploads and search are coming soon, so anything here that needs them is something you add yourself for now.

FAQ

When should I worry about scale for a SaaS dashboard?
Not before a measured trigger fires. For example, for "Custom roles and fine-grained permissions": 3+ customers ask for custom roles.
What performance targets should a SaaS dashboard aim for?
Dashboard page (authenticated) TTFB: p95 < 400 ms with <= 12 queries, every chart one indexed read. Public API request: p95 < 150 ms for reads, p99 < 400 ms for writes, <= 5 queries. Usage ingest: p99 < 100 ms per batch, one INSERT per batch.
Does Forge64 cap my usage costs?
Yes. Every metered resource has a hard cap, and paid plans add an overage spend cap that you set.

Build your app with Forge64

One prompt to a running app with auth, database, hosting and payments. Start free, no credit card required.

Start building for free