Skip to content

Billing

Usage-based billing from per-minute pod snapshots. Shuttle snapshots running pods every 60s to Starbase, which keeps a Postgres running total plus a ClickHouse audit trail; a monthly cron applies the plan credit and generates a Stripe invoice.

Load-bearing — cost from resource requests, not labels

Cost is computed from the pod's resource requests (CPU/memory in the PodSpec), not from labels — the starform.io/tier label is denormalized for display/analytics only (§24.1). Tier name → price is a Starbase-side lookup from resource requests at billing time. Billing-staleness is watched by Grafana Cloud (§35.5).

§36.1 End-to-End

flowchart TB
  classDef built fill:#3434DC22,stroke:#3434DC,color:#5B5EE8;
  classDef third fill:transparent,stroke:#808080,color:#808080;
  classDef store stroke-dasharray:4 3,stroke:#808080;

  SHUTTLE["Shuttle<br/>every 60s"]:::built
  API["Starbase API"]:::built
  PG[("Postgres<br/>running totals · dashboard + Stripe invoicing")]:::store
  CH[("ClickHouse<br/>immutable audit trail · dispute resolution")]:::store
  WORKER["Starbase Worker<br/>monthly cron · queries Postgres running totals"]:::built
  STRIPE["Stripe<br/>generates invoice per customer · charges customer"]:::third

  SHUTTLE -- "POST /api/v1/clusters/{id}/snapshots" --> API
  API -- "dual-write" --> PG
  API -- "dual-write" --> CH
  PG --> WORKER
  WORKER -- "generate invoice" --> STRIPE
Diagram — Billing flow, end to end. Shuttle snapshots running pods every 60s → Starbase API dual-writes to Postgres (running totals) and ClickHouse (immutable audit) → the Worker's monthly cron reads Postgres totals and generates a Stripe invoice per customer. Brand-blue = Starform-built; dashed = data store; gray = third-party.

§36.2 Billing Model

  • Per-minute billing (not per-second) — matches Railway, simpler operationally
  • Instance-based — pod existence = billable, not CPU/memory utilization
  • Snapshot reconciliation — periodic snapshots (not event-driven start/stop) avoids the fatal flaw of lost "stop" events causing infinite billing
  • Idempotent ingestion — deterministic snapshot_id prevents double-counting on retries

§36.3 Edge Cases

Edge case How handled
Mid-month tier change Pod recreated at new tier, naturally reflected in snapshots
Customer pod deleted Snapshots stop containing that pod, no infinite billing
Shuttle disconnect Resumes on reconnect, max 60s loss per disconnect
Billing dispute Query ClickHouse audit trail for exact pod-level history
Failed payment Starbase Worker suspends services via desired state (sets replicas to 0)

Tiers & pricing

Pod instance sizes are the customer-facing Nova tiers (§1). Price maps to the pod's resource requests at billing time (see the load-bearing note above) — the tier name is a denormalized label only.

Tier Nova Name CPU RAM Price
Hobby (shared) Mininova Shared 512 MB $5/mo
Dedicated entry Micronova 0.5 vCPU 512 MB $18/mo
Dedicated mid Nova 1 vCPU 2 GB $36/mo
Dedicated growth Supernova 2 vCPU 4 GB $85/mo
Dedicated scale Hypernova 4 vCPU 8 GB $175/mo
Dedicated premium Ultranova 4 vCPU 16 GB $250/mo

Cross-references

Per-pod cost is derived from resource requests, not the tier label → §24.1 · the snapshot is delivered through the desired-state loop → §32 · Shuttle's billing-staleness gauge → §26.1 · the ClickHouse audit store → §35.1 · Nova tier names → §1. Canonical map: Canonical Sources.