Performance

static.bio treats performance as a product constraint, not an implementation detail.

Public profiles are optimized for:

  • small payloads
  • fast server response
  • predictable rendering (no client runtime)

This page defines what we measure, what we target, and how to verify it.


Performance goals

Public profile budgets (targets)

These are targets, not promises of physics across every geography and cache state:

  • HTML payload: small and stable per profile
  • CSS payload: ≤ 2 files (base + theme), cacheable and fingerprinted
  • No JS: public pages ship 0 <script> tags
  • Fast TTFB: optimized for low-latency responses under normal load

Budgets are validated via automated checks (see Contract tests and Verify).

Performance snapshot

static.bio — performance snapshot
runs: 10 • device: Desktop (Chromium) • headless: true
TTFBAvgp95Notes
Warm cache18ms28mssame context
Cold cache22ms52msnew context
Parallel (N=10)23ms50ms10 concurrent
Page specValueNotes
Page transfer (cold)7.30KBHTML+CSS+avatar (+headers)
Page transfer (warm)4.94KBHTML only; CSS cached
Third-party requests0same-origin only
CSS files2base + theme
Methodology
  • Harness
    • All measurements use Playwright + Chromium (headless), Desktop profile, no throttling.
    • Tests target production (https://static.bio) to capture real-world behavior: edge routing, HTTP/2 connection pooling, and geographic latency.
  • TTFB
    • Definition: TTFB is computed from the browser's Navigation Timing API as: responseStart - requestStart This includes DNS, TCP, TLS, and server processing as observed by the browser.
    • Warm cache (same context / pooled connection)
      • After warm-up navigations, run 5 batches × 10 concurrent navigations in the same browser context (50 samples).
      • Purpose: measure TTFB under burst while preserving HTTP/2 connection reuse.
    • Cold cache (new context per sample)
      • For each run, create a fresh browser.newContext(), navigate once, record TTFB, then close the context.
      • 20 samples, with 500ms between runs.
      • Purpose: isolate the cost of new connections (DNS/TCP/TLS) without reuse.
    • Parallel cold (new contexts, concurrent)
      • Run 5 batches × 10 concurrent navigations, each in a fresh context (50 samples).
      • Purpose: measure contention under concurrent new connections.
    • Note on correctness: Warm-cache measurement uses concurrency on a reused connection pool (not sequential requests on a single page) to avoid conflating "time passing" variance with connection reuse effects.
  • Page spec
    • Page transfer (cold / warm)
      • Uses Resource Timing entries: performance.getEntriesByType("resource")
      • Computes sum of transferSize across resources.
      • transferSize includes headers + compressed body, and becomes 0 for cache hits.
      • Cold = first visit; Warm = second visit with cache retained.
    • Third-party requests
      • Compares each resource's origin against the document origin (same-origin policy).
      • Excludes the user-provided avatar URL so the metric reflects platform-controlled resources only (verifying the "same-origin" guarantee for static.bio assets).
  • Measurement challenges (what we fixed)
    • Node fetch vs browser TTFB: Node.js fetch() does not reflect browser HTTP/2 pooling or proximity. We measure TTFB via Navigation Timing instead.
    • Load timing definition: "networkidle" introduces a fixed quiet-window delay; we use waitUntil: "load" and load-event timing for end-to-end measurements.
    • FCP in headless: paint timing is unreliable in headless.
    • Connection isolation for cold runs: cold scenarios close contexts after each measurement and introduce delays to reduce accidental reuse.
  • Statistics
    • Scenarios use 20–50 samples each.
    • Percentiles are computed on sorted samples using index floor(n * 0.95).
    • Display rounding avoids visual artifacts:
      • ms values can be shown at 0–1 decimal precision as needed.
      • KB values are displayed to 2 decimals; p95 display is rounded such that it cannot appear lower than avg due to rounding.

What "fast" means here

Performance is not only about raw time; it's about removing classes of work:

  • No client-side runtime → no JS parse/execute
  • No third-party resources → no slow external dependencies
  • Deterministic renderer → stable output, cacheable primitives
  • Fingerprinted CSS → aggressive reuse across profiles

The result is a page that becomes "free" on repeat visits: the browser cache holds base/theme CSS, and the HTML is minimal.

Metrics we care about

Server-side

  • TTFB (time to first byte)
  • p95 / p99 TTFB (tail latency matters)
  • cache hit ratio (if you cache rendered HTML)
  • response size (compressed)

Client-side

  • bytes transferred (compressed)
  • render blocking resources (should be CSS only)
  • number of requests
  • LCP/FCP in typical conditions (no JS makes these mostly a function of CSS and images)

Why we accept 2 CSS requests

Public profiles load:

  • base.<hash>.css
  • theme-<id>.<hash>.css

This is intentional:

  • Those files are shared across many profiles.
  • They are served with immutable caching headers.
  • After the first visit, they typically cost 0 bytes (cache hit).

We optimize for cacheability and byte budget, not "single-response pages."

Export mode is the exception: it may inline CSS for portability.

Measurement methodology

1) Over-the-wire bytes

Measure compressed bytes from the server. Example:

  • HTML bytes (compressed transfer) for a profile
  • CSS bytes (compressed transfer) for base and a theme

2) Request audit

Verify that public pages:

  • include no scripts
  • load only same-origin resources
  • load ≤ 2 stylesheets

3) Tail latency

Measure p95/p99 TTFB in production-like conditions, not only locally.

The renderer itself is cheap; tail latency is typically dominated by:

  • data store latency
  • cold starts / scaling events
  • geography
  • cache state

Practical optimizations (what we do and don't do)

We do

  • Keep HTML structure stable
  • Prefer CSS variables and theme deltas
  • Fingerprint and immutable-cache CSS assets
  • Avoid third-party assets
  • Keep image usage minimal (avatar only, unless the user adds more later)

We avoid

  • Client-side hydration
  • third-party analytics scripts
  • heavy font loading by default
  • "hero section" layout complexity

Known tradeoffs

  • Geography matters. A Toronto request and a Singapore request will not have the same TTFB.
  • Cold caches happen. The first request after deployment or cache eviction is slower.
  • Avatars can dominate LCP. If avatars are large or external, they can become the slowest resource.
  • Per-profile CSS inlining doesn't scale. It reduces requests but destroys shared caching; we prefer shared assets.

Contract tests (performance-level)

These are invariants we can assert mechanically:

  • Public HTML contains 0 <script> tags.
  • Public HTML loads ≤ 2 stylesheets (base + theme) in non-export environments.
  • All stylesheet URLs are same-origin (prefer relative paths).
  • Base/theme CSS filenames are fingerprinted and served with immutable caching headers.
  • Total transferred bytes for HTML stay under a defined ceiling (set a CI threshold).

Exact commands and expected outputs live in Verify (curl cookbook).

How to verify

See: Verify (curl cookbook) for copy/paste commands that measure:

  • bytes transferred
  • number of stylesheet links
  • presence of scripts
  • response headers and caching behavior