SaaS Performance Optimization: The Complete Edge-First Guide for 2026

Ein vollständiger Production-Guide zur SaaS-Performance-Optimierung über CDN, Edge Compute, D1, SSR und Core Web Vitals — mit TanStack Ships erprobten Defaults.

Huifer
Huifer
26. Juni 202610 min read
Auch verfügbar auf:English · 中文

Geschrieben von Huifer, Solo-Entwickler und Maintainer von TanStack Ship. Ich betreibe 12+ Production-SaaS-Apps auf Cloudflare Workers + D1 und jage seit drei Jahren sub-200ms p95-Latenz am Edge. Dieser Guide ist die Synthese jeder Default-Einstellung, die in TanStack Ships 14 Modulen ausgeliefert wird — Patterns, die ich bei echten paying Customers getestet habe, nicht bei theoretischen Benchmarks. Wo ich eine Skala nicht validiert habe (50k req/s, Multi-Region-Failover), sage ich das explizit.

Verifizierte Quellen: Cloudflare Workers Docs · Cloudflare D1 Docs · Web Vitals · TanStack Router · TanStack Ship GitHub

Zuletzt aktualisiert: 26. Juni 2026 · Changelog


TL;DR

SaaS-Performance-Optimierung ist nicht eine Sache — es sind vier Layer, die sich potenzieren: Netzwerk (CDN + Edge Compute), Datenbank (D1 + SQLite-Patterns), Frontend (TanStack Start SSR + Hydration) und Observability (Real User Monitoring + Performance Budgets). Die meisten Gründer optimieren zuerst den falschen Layer. Das 80/20-Prinzip liegt beim CDN und Edge-Cache: eine TTFB-Reduktion um 300ms dort schlägt jede Frontend-Micro-Optimierung. Danach liefern D1-Query-Patterns (Indexes, gebatchte Writes über Cloudflare Queues) und TanStack Starts Streaming SSR die nächsten Ordnung-Gewinne. Dieser Guide durchläuft jeden Layer mit den exakten Konfigurationen, die TanStack Ship in Production einsetzt.


Warum Performance ein Umsatzproblem ist, kein Tech-Problem

Bevor es an die Optimierung geht, möchte ich den Gesprächskontext verschieben. Performance ist kein Engineering-Thema, das in einem Lighthouse-Tab lebt — es ist ein Conversion-Rate-Hebel mit dem höchsten ROI jeder SaaS-Intervention.

Die Mathematik ist schonungslos. Für B2B SaaS reduziert eine Erhöhung des LCP um 100ms die Conversion um ca. 7%. Bei B2C-Checkout-Flows kürzt dieselbe Verzögerung den Seitenwert um ähnliche Margen. Stripes eigene internen Daten (öffentlich zitiert von ihrem Team) zeigen, dass Checkout-Abbrüche steil ansteigen, sobald die Gesamtladezeit 2 Sekunden überschreitet. Jede Millisekunde, die Sie zwischen 800ms und 1,5s p75 LCP einsparen, hat einen messbaren Dollar-Return.

Dieser Rahmen ist wichtig, weil er zeigt, wo Sie zuerst investieren sollten. Wenn Ihr Checkout 1,8s braucht und Ihre Homepage 0,9s — dann beginnen Sie nicht mit Code-Splitting der Marketing-Seite. Sie beginnen mit dem Checkout, wo der Umsatz liegt. Performance-Arbeit ohne Revenue-Attribution ist Engineering-Unterhaltung.

Eine nützliche Plausibilitätsprüfung, die ich bei jedem TanStack-Ship-Kunden durchführe: Bevor Sie Optimierungsarbeit beginnen, erfassen Sie einen 7-Tage-RUM-Baseline, markieren Sie, welche Routes Umsatz generieren (Checkout, Signup, MRR-Dashboard für Admins), und ranken Sie die Optimierungen nach (Latenz-Einsparung) × (Umsatz pro Request). Die Top 3 kommen meist aus dem CDN-Layer und dem Datenbank-Write-Path — niemals aus der Frontend-Framework-Wahl.


Die vier Layer der SaaS-Performance

Ich betrachte SaaS-Performance als vier orthogonale Layer, und die meisten SaaS optimieren nur einen davon:

1. Netzwerk-Layer (CDN + Edge Compute)

Der erste Byte, den ein User erhält. Dazu gehören CDN-Cache-Hit-Ratio, Edge-Function-Cold-Start und geografische Entfernung zum Ursprung. Hier kann eine einzige Konfigurationsänderung den TTFB von 800ms auf 80ms senken. Es ist der Layer mit dem größten Hebel für nahezu jedes SaaS.

2. Datenbank-Layer (D1 / SQLite / Postgres)

Query-Latenz, Index-Abdeckung und Lock-Kontention. Für D1 spezifisch ist der Write Lock ein globales Flaschenhindernis — Details dazu finden Sie in meinem D1-Write-Lock-Postmortem mit dem vollständigen Vorfall bei 200 req/s. In diesem Layer entstehen die meisten „wir haben ein Performance-Problem"-Tickets.

3. Frontend-Layer (SSR + Hydration + Bundle)

Time to Interactive, Hydration-Kosten, JavaScript-Bundle-Größe. TanStack Starts Streaming SSR verschafft Ihnen hier einen echten Vorteil gegenüber einem client-gerenderten SPA — aber nur, wenn Sie es korrekt einsetzen. Ein 400KB großes JS-Bundle ruiniert Ihren LCP, egal wie gut Ihr SSR ist.

4. Observability-Layer (RUM + Performance Budgets)

Was Sie nicht messen können, können Sie nicht optimieren. Real User Monitoring (RUM) über die Web Vitals-Bibliothek ist das einzige Signal, das Ihre tatsächlichen Customers widerspiegelt. Synthetic Lighthouse-Runs eignen sich zum Erkennen von Regressions, nicht als primäres Optimierungsziel.

Der größte Fehler, den ich beobachte: Gründer verbringen 80% ihrer Performance-Zeit mit Layer 3 (Frontend-Micro-Tweaks), obwohl Layer 1 allein denselben Conversion-Lift mit einer einzigen Konfigurationsänderung liefern könnte. Wenn Sie nur Zeit haben, einen Layer zu optimieren, dann den CDN.


Layer 1: Edge-Netzwerk und CDN — Das 80/20

Die einzelne Änderung mit dem höchsten ROI bei der SaaS-Performance ist die korrekte CDN-Konfiguration. Für TanStack-Ship-Kunden bei Cloudflare lautet die Default-Konfiguration, die ich ausliefere:

toml
# wrangler.jsonc
{
  "rules": [
    {
      "description": "Static assets — 1 year cache",
      "expression": "(http.request.uri.path ~ '\\.(css|js|woff2|png|jpg|svg|webp|avif)$')",
      "actions": {
        "cache": { "ttl": 31536000 }
      }
    },
    {
      "description": "Dynamic HTML — stale-while-revalidate",
      "expression": "(http.request.uri.path eq '/' or http.request.uri.path ~ '^/blog')",
      "actions": {
        "cache": {
          "ttl": 300,
          "serve_stale": {
            "status": [200],
            "stale_while_revalidate": 86400
          }
        }
      }
    }
  ]
}

Der stale-while-revalidate-Block ist der Trick, der Cache-Frische ohne Cache-Miss-Penalty ermöglicht: Users sehen die stale Version sofort, während eine Hintergrundanfrage den Cache auffrischt. Das ist es, was sich 300s-TTLs für Users nahtlos anfühlen — auch nach Deployments.

Static-Asset-Caching-Strategie

Statische Assets (CSS, JS, Fonts, Icons) sollten ein Jahr gecacht werden, fingerprinted durch Content-Hash im Dateinamen. Cloudflares Edge-Cache ist global mit 330+ Standorten und ~50ms p50 zu den meisten Users weltweit. Der CDN erledigt die Arbeit — Ihr Origin nicht. Im CDN-Auswahl- und Konfigurations-Guide finden Sie Provider-Vergleiche, falls Sie noch nicht bei Cloudflare sind.

Edge-Caching für dynamische Inhalte

Dynamisches HTML ist der schwierigere Fall. Reines HTML-Caching funktioniert nicht, wenn die Inhalte user-spezifisch sind (eingeloggte MRR-Dashboards, personalisierte Preise). Das Pattern, das ich standardmäßig in TanStack Ship ausliefere:

  1. Anonyme Marketing-Routes 300s mit stale-while-revalidate cachen.
  2. Cache für authentifizierte Routes komplett umgehen (Cookies: tb_session).
  3. API-Responses 0–60s mit der Workers Cache API cachen für Routes, die read-heavy sind aber Staleness tolerieren.

Der Trick ist die Route-Segmentierung — TanStack Routers dateibasiertes Routing macht dies trivial, weil Cache-Regeln auf spezifische Route-Trees abzielen können.

Ein Hinweis zu Vercel Edge und AWS CloudFront: Beides sind glaubwürdige Alternativen, und ich habe auf beiden ausgeliefert. Vercels Edge-Netzwerk ist schnell, bindet Sie aber an Next.js; CloudFronts Reichweite ist breiter, aber die Konfigurationsfläche ist größer. Cloudflares Kombination aus CDN + Workers + D1 + R2 in einem Stack ist der Grund, warum TanStack Ship dort standardisiert — weniger Vendors, weniger Integrations-Bugs.


Layer 2: Datenbank-Performance — D1- und SQLite-Patterns

Cloudflare D1 ist SQLite am Edge, was bedeutet: schnell und mit einem Write-Lock-Ceiling. Die D1-Query-Optimierungstechniken habe ich woanders ausführlich behandelt; die Production-getesteten Defaults, die ich ausliefere:

Index-Strategie für Multi-Tenant SaaS

sql
-- Every tenant-scoped table needs a composite index on (tenant_id, created_at)
CREATE INDEX idx_subscriptions_tenant_created
  ON subscriptions(tenant_id, created_at DESC);

-- Foreign keys should always have indexes
CREATE INDEX idx_invoices_subscription_id
  ON invoices(subscription_id);

-- JSON columns used in WHERE clauses need generated columns + indexes
ALTER TABLE subscriptions ADD COLUMN plan_tier TEXT
  GENERATED ALWAYS AS (json_extract(metadata, '$.tier')) VIRTUAL;
CREATE INDEX idx_subscriptions_plan_tier ON subscriptions(plan_tier);

Der zusammengesetzte Index (tenant_id, created_at DESC) ist der am häufigsten fehlende Index in SaaS-D1-Schemata. Jede Listenabfrage auf einer Tenant-scoped Table braucht ihn. Das GENERATED ALWAYS AS-Pattern ermöglicht es, in JSON-Spalten zu indexieren, ohne Daten zu duplizieren.

Die Write-Lock-Falle

Wenn Ihr SaaS dauerhaft >50 Writes pro Sekunde auf D1 hat, werden Sie auf SQLite's globalen Write Lock treffen. Das ist kein D1-Bug — das ist die Funktionsweise von SQLite. Die Lösung ist das Queue- und Workflow-Pattern, das ich im D1-Write-Lock-Postmortem dokumentiert habe. Bei 50k req/s habe ich das nicht getestet — die Production-Deployments, die ich betreibe, erreichen ~600 Writes/sec im Peak — aber das Pattern ist solide für die gesamte D1-Einhüllende.

Für TanStack-Ship-Kunden enthält das Billing-Modul dieses Queue-basierte Batching standardmäßig, sodass das Failure Mode, das ich im Februar 2026 bei 200 req/s hatte, in dem Template schlicht nicht auftritt.


Layer 3: Frontend-Performance — TanStack Start SSR

TanStack Starts Streaming SSR ist wirklich gut, aber nur, wenn Sie die üblichen Fallstricke vermeiden.

Streaming SSR richtig gemacht

TanStack Start streamt HTML-Chunks, sobald sie bereit sind. Der erste Chunk sollte den Above-the-Fold-Hero und die primäre CTA enthalten — alles unterhalb des Folds kommt später. Die Falle: Awaiten Sie keine Datenbankaufrufe in der SSR-Phase, die den ersten Chunk blockieren. Nutzen Sie Suspense-Boundaries, damit die Hero-Shell streamt, während langsamere Queries sich auflösen.

Bundle-Hygiene

Ein 400KB großes JavaScript-Bundle ruiniert Ihren LCP, egal wie gut der Server antwortet. Die Hygieneregeln, die ich in TanStack Ship durchsetze:

  • Route-Level-Splitting (TanStack Router macht das automatisch).
  • Keine lodash-Imports — nutzen Sie lodash-es per-Method-Imports oder native Äquivalente.
  • Datumsbibliotheken: bevorzugen Sie die native Intl API über Moment.
  • Icon-Bibliotheken: aggressiv Tree-shaken; ein Icon = eine Komponente.

Image-Optimierungspipeline

Für SaaS sind Bilder oft der größte Payload. Die Pipeline, die ich ausliefere:

  1. Quellbilder als AVIF, wo unterstützt, WebP als Fallback.
  2. <img> mit srcset für responsives Sizing verwenden.
  3. Alles unterhalb des Folds lazy-loaden mit loading="lazy".
  4. Kritische Above-the-Fold-Bilder mit <link rel="preload" as="image"> vorladen.

Einen Fehler, den ich 2025 gemacht habe: Ein „schneller" LCP-Wert aus synthetischem Lighthouse kann einen schlechten Real-User-LCP maskieren, weil Lighthouse von einem einzigen Rechenzentrum mit idealen Netzwerkbedingungen aus läuft. Kombinieren Sie Lighthouse immer mit RUM, bevor Sie Erfolg verkünden. Der synthetische Score ist ein Regressionsdetektor; der RUM-Perzentilwert ist die Wahrheit.


Layer 4: Observability — Performance Budgets

Die günstigste Versicherung gegen Performance-Regressions ist ein Performance Budget, das in der CI erzwungen wird. Das Pattern:

typescript
// performance-budget.ts
export const budget = {
  // Bundle size budgets (gzipped)
  maxJsBundleKb: 180,
  maxCssKb: 40,
  maxInitialImageKb: 120,

  // Core Web Vitals (p75)
  maxLcpMs: 1800,
  maxInpMs: 200,
  maxCls: 0.05,

  // Server timings
  maxTtfbMs: 200,
  maxDbQueryMs: 50,
};

// In CI, fail the build if any budget is exceeded
export function checkBudget(measurements: typeof budget) {
  for (const [key, limit] of Object.entries(budget)) {
    const actual = measurements[key as keyof typeof budget];
    if (typeof actual === 'number' && actual > limit) {
      throw new Error(`Performance budget exceeded: ${key} = ${actual}, limit = ${limit}`);
    }
  }
}

Dieses Budget-Check führe ich in der CI bei jedem Pull Request durch. Sobald ein Feature-Branch ein Budget überschreitet, schlägt der Build fehl. Diese eine Ergänzung hat mehr Performance-Regressions verhindert als alle anderen Taktiken zusammen.

Das Deployment-Sequenz, das ich empfehle: RUM zuerst ausliefern (ein Nachmittag, um Web Vitals in die Route-Komponenten einzubinden), dann Budgets in der CI setzen (ein Tag), dann die langsamsten Routes nach RUM p75 optimieren (laufend). RUM ohne Budgets gibt Ihnen Zahlen ohne Durchsetzung; Budgets ohne RUM gibt Ihnen synthetische Zahlen, die nicht die realen Users widerspiegeln. Beides wird benötigt.


Der TanStack Ship Performance Stack

TanStack Ship liefert alle vier Layer vorkonfiguriert aus. Sie starten nicht bei Null — Sie starten bei Production-Defaults.

Was standardmäßig ausgeliefert wird

  • CDN-Regeln in wrangler.jsonc: Static-Asset-Cache, Dynamic-HTML stale-while-revalidate, API-Response-Cache.
  • D1-Schema-Migrations für die 14 Module: Jede Tenant-scoped Table hat den zusammengesetzten Index, jede JSON-Query-Spalte ist generiert und indiziert.
  • TanStack Start Routes mit korrekten Suspense-Boundaries und Streaming SSR.
  • Performance Budget in der CI verdrahtet; PRs scheitern bei Regression.
  • RUM via Web Vitals in Production, mit p75-Dashboards pro Route.

Was Sie konfigurieren

Jedes SaaS hat eine andere Traffic-Form. Sie passen die Cache-TTLs pro Route an, justieren die RUM-Alert-Schwellenwerte und fügen Custom-Indexes für domänenspezifische Query-Patterns hinzu. Aber Sie starten mit Production-Defaults, nicht mit leeren Blättern.

Unter TanStack Ship Features finden Sie die vollständige Modulliste, oder gehen Sie direkt zu Preise, um zu sehen, was zu Ihrer Stage passt.


Fazit

SaaS-Performance-Optimierung ist ein Vier-Layer-Problem, und die Layer potenzieren sich. Ein 100ms CDN-Gewinn plus 100ms Datenbankgewinn plus 100ms SSR-Gewinn ergibt eine 300ms LCP-Verbesserung — das entspricht roughly einem 20% Conversion-Lift für einen B2B-SaaS-Checkout. Keiner dieser Gewinne erfordert ein Rewrite; sie erfordern die richtigen Defaults und ein Performance-Budget, das Regression verhindert.

TanStack Ship liefert diese Defaults aus, weil ich am eigenen Leib erfahren habe, was ohne sie passiert. Drei Jahre Production-Incidents, destilliert in 14 Module, die Sie von Beginn an zu sub-200ms p95 bringen. Free Starter klonen →