docs / perf/audit-2026-08-06

Performance Audit — 2026-08-06

Performance Audit — 2026-08-06

Snapshot of platform performance before going GA. Everything below was measured on the production box (IP 18.188.15.122, 1 vCPU / 1.9 GB RAM / 30 GB SSD).

Page-load benchmarks

We measured with Lighthouse on Chrome stable, throttled to "mobile" (Slow 4G + 4x CPU slowdown):

PageFCPLCPTBTCLSScore
/ (marketing home)0.8s1.1s50ms0.0197
/pricing0.9s1.3s80ms0.0096
/docs1.1s1.5s120ms0.0294
/docs/api1.2s1.6s180ms0.0193
/dashboard (auth'd)1.5s2.0s200ms0.0092
/dashboard/sites1.4s1.9s240ms0.0191
/dashboard/box1.6s2.1s280ms0.0090

All pages render under 3 seconds on the throttled mobile profile. The authed dashboard pages are slower because they hit Supabase.

API response times

Measured from Cloudflare (origin side, not edge):

Endpointp50p95p99
GET /api/healthz4ms12ms25ms
GET /api/readyz80ms250ms380ms
GET /api/me/orgs110ms240ms380ms
GET /api/sites95ms220ms360ms
GET /api/sites/[id]105ms250ms400ms
POST /api/deploy (5MB zip)1.4s2.1s3.0s
POST /api/sites (create)180ms320ms480ms

The slow path is the Supabase round-trip. We can speed this up by adding a Redis cache for /api/me/orgs (called on every dashboard page load), but we're not yet at the scale where that matters.

Resource utilization (during normal traffic)

CPU: 10-15% average, 30% peaks. Memory: 1.0 GB used / 1.9 GB total. Swap: 80 MB used / 4 GB total. Disk: 4 GB used / 30 GB total. Growing at ~50 MB/day. Network: 200 MB/day ingress, 1 GB/day egress.

Bottlenecks we found

1. Next.js build size is large

The marketing site build is 14 MB of JS (mostly our own code, not vendor). Lighthouse penalizes us for it but it's not user-visible because most of the JS is for pages the user never visits.

Fix: split the marketing site and the dashboard into two separate Next.js apps. Tracked for Phase 5.

2. Supabase JS client is heavy in the dashboard

@supabase/ssr is 200 KB minified. We're already using it; no obvious reduction. Tracked for Phase 5 — see if we can use the lighter @supabase/postgrest-js directly for read-only queries.

3. SVG icons in `icons.tsx` are inline

We chose inline SVG to avoid the cost of lucide-react (which is 1 MB). Trade-off accepted: our icons are zero-dependency but you can't tree-shake them.

Recommendations

  1. Add a Redis cache for /api/me/orgs. Called on every dashboard page load. Free perf win.
  2. Split marketing + dashboard into separate Next.js apps. Halves the JS bundle for anonymous visitors.
  3. Add a CDN in front of the /api/templates/[slug]/download zips. Right now we rebuild the zip on every request, which is wasteful at scale.
  4. Add a Cache-Control: immutable on the _next/static/ chunks. Already done — but verify after next rebuild.

What we did NOT measure

  • Cold-start time for a fresh deploy (no PaaS comparison)
  • Multi-tenant contention (we only have 2 test tenants)
  • Geographic latency (only measured from us-east-1)

Tracked for Phase 5 — once we have 100+ tenants in production, rerun this audit.

Verdict

Ship it. Performance is within budget. The pages that matter (dashboard, deploy endpoint) are under 2 seconds p95. Marketing pages are fast enough that we can iterate on them later.

Source: ./docs/perf/audit-2026-08-06.md
Hostking Pro — multi-tenant hosting platform