Skip to content

Cost & Scaling ​

What the platform costs to run, and what has to change as it grows.

These are list-price estimates

Derived from the Terraform configuration and DigitalOcean's published pricing. Validate against the actual invoice — usage-based services (Mux, Spaces bandwidth, CDN) vary with traffic, and make cost in infra/terraform deliberately points you at the DigitalOcean calculator rather than guessing.

Fixed monthly cost ​

ItemConfiguration≈ / month
Kubernetes nodes3 × s-4vcpu-8gb$144
Kubernetes control planeStandard$0
Managed PostgreSQLdb-s-2vcpu-4gb, 1 node$60
LiveKit droplets-4vcpu-8gb$48
Load Balancer1$12
Container RegistryBasic tier$5
SpacesBase, 250 GB included$5
Block storage25 GB (Loki 20 Gi + Redis 5 Gi)$3
Subtotal≈ $277

Usage-based ​

ServiceDriverNotes
MuxMinutes encoded, minutes deliveredThe most variable line. Video-heavy growth shows up here first
Spaces bandwidthCDN egress beyond the included allowanceGrows with media consumption
Node autoscalingLoadPool scales 2–10; each extra node is $48
RevenueCatTransaction volumeFree below a revenue threshold, then a percentage
StripePayout volumePer-transfer fees
Expo / EASBuild minutes

Realistically $300–450/month all-in at modest usage, with Mux the line most likely to surprise.

Cost levers ​

LeverSavingTrade-off
Drop to 2 nodes−$48Less headroom; autoscaling still covers bursts
Smaller LiveKit droplet−$24Fewer concurrent voice participants
Self-hosted Postgres in-cluster−$60You own backups, failover, and upgrades. Not recommended
Spaces lifecycle rules on originalsStorageOriginals are currently kept forever after processing
Loki retention policyStorageCurrently unbounded until the 20 Gi fills

A single-droplet alternative exists on paper

dev-notes/single-droplet-feasibility-analysis.md concludes the whole stack fits on one 4 GB / 2 vCPU droplet (~$24/month plus external services) for 200–500 concurrent users.

That is a genuine option for a much earlier stage, but it trades away everything Kubernetes is providing here: zero-downtime rollouts, replica-level redundancy, autoscaling, and managed database backups. Given the platform is live and handling real money, the current setup is the right call. Note also that the analysis's comparison figure ($148–153/month) reflects a smaller cluster than the one currently configured.

What breaks first as you grow ​

In the order it will actually happen:

1. Database connections ​

db-s-2vcpu-4gb has a bounded connection limit. Three API replicas plus esu, ogun, anansi, and igdb-heartbeat each hold a Prisma pool. Adding API replicas multiplies connections, so the database limit caps horizontal scaling of the API before CPU does.

Fix: a connection pooler (PgBouncer, or DigitalOcean's managed pooler). Cheap, and it should be done before scaling the API.

2. Redis as a single point of failure ​

One replica backing the queue, realtime fan-out, caching, and the payout lock. A restart interrupts all four.

Fix: DigitalOcean Managed Redis with HA. Roughly $15–60/month depending on size.

3. redis.keys() on every post ​

Feed cache invalidation calls KEYS, which is O(N) over the entire keyspace and blocks the Redis server while it runs. At current volume it is invisible; as the keyspace grows it becomes a latency spike felt by every service sharing that Redis.

Fix: SCAN, or track each user's cache keys in a Redis set. Contained change, no infrastructure cost.

4. The discover feed ​

prisma.user.findMany() with no limit — it returns every user on the platform. It will get slower in proportion to signups and eventually time out.

Fix: proper ranking, filtering, and pagination. See Discovery.

5. Presence across esu replicas ​

Resolved: presence is derived from live sockets via the Redis adapter's fetchSockets(), so it is consistent across replicas. The remaining cost is one cross-pod fetchSockets() per presence change and per subscribed user, which grows with watchers; a Redis-backed cache is the next step if that shows up. See Realtime.

6. Media processing throughput ​

ogun autoscales 2–8 on CPU, which handles bursts. The next ceiling is Mux's rate limits on asset creation.

7. Mux costs ​

Encoding and delivery both scale with video volume. Watch this line specifically as clip usage grows; video_quality: "basic" is already the economical setting.

Scaling actions in order ​

SignalActionCost
API CPU sustained highAdd API replicas — but check database connections first$0 until a node is added
Postgres connection errorsAdd a connection pooler~$15
Nodes at capacityThe pool autoscales to 10$48 per node
Redis latency or restartsMove to Managed Redis with HA$15–60
Database CPU or storage pressureResize the managed clusterStep up in tiers
Media backlog growingogun HPA handles it; raise maxReplicas if neededNode cost only
Voice quality degradingLarger LiveKit droplet, or a second one$24–48

Things worth spending money on ​

Not all of these are infrastructure, and the non-infrastructure ones are the better investment:

InvestmentCostReturns
Staging environment$30–50/monthStops untested changes reaching production. Highest value per dollar here
Managed Redis$15–60/monthRemoves a single point of failure
Connection pooler~$15/monthUnblocks API scaling
CI/CD$0 (GitHub Actions free tier)Automated verification and traceable deploys
Alerting$0 (Grafana already deployed)Find outages before users report them
Uptime monitoring$0–10/monthCatches the case where the cluster is down and therefore not logging

Three of the six cost nothing and are limited only by engineering time.

Efficiency already in place ​

Worth noting, because it is the reason costs are as low as they are:

  • Aggressive image caching (max-age=31536000, immutable) — the CDN serves almost everything
  • Redis caching on the feed (60 s) and trending (5 min) — the expensive queries run rarely
  • Presigned direct-to-Spaces uploads — media bytes never consume API bandwidth or CPU
  • video_quality: "basic" on Mux — the cheaper encoding tier
  • withoutEnlargement on image resizing — no wasted work upscaling small originals
  • Node autoscaling from 2 — the cluster scales down when idle

Internal documentation — PlayPalz platform