RORK LABJP
TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the roundTOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round
Articles/Dev Tools
Dev Tools/2026-05-31Advanced

Running Crash-Free Rate as a Budget: An SLO Design Note for Deciding Where to Invest Across 6 Indie Apps

Notes from running 6 wallpaper apps in parallel and the shift from treating crash-free rate as a pass/fail threshold to treating it as an error budget. A working write-up on turning burn rate into investment and sunset decisions.

Rork515SLOCrashlytics12Cloudflare Workers24Reliability2AdMob70

Premium Article

One of my apps dropped from 99.7% to 99.2% crash-free right after a release. Half a percentage point. And I genuinely could not decide whether to pause the next feature and dig into the cause, or treat it as ordinary noise and keep moving. I had no internal sense of whether 99.2% was "dangerous" or "fine."

I have been building apps independently since 2014 — twelve years now — and somewhere after crossing 50 million cumulative downloads, this question of how to judge fragility started following me everywhere. With a single app, intuition is enough. But running 6 wallpaper and calming apps in parallel means deciding, almost weekly, where to spend my time: which app to grow, which to wind down. This post is about the moment I stopped looking at crash-free rate as a pass/fail number and started treating it as an error budget — and how I turned that number into investment and sunset decisions, with the actual figures and code behind it.

A pass/fail threshold makes your judgment wobble

When I ran crash-free rate as "above 99% is fine, below means act," my decisions were shockingly inconsistent. The same 99.2% would feel "still okay" on a good morning and "we're in trouble" on a tired evening — so I'd freeze everything and start investigating. My judgment was tracking my mood, not the app.

The real problem is that a threshold only ever looks at the instantaneous value. Crash-free rate jumps around daily. On a low-DAU app, a single user crashing repeatedly can swing it 0.3 points. Decide feature freezes off the instantaneous number and you either get whipsawed by noise or miss a slow, steady decline.

This is exactly where the SRE idea of an SLO (Service Level Objective) and error budget earns its keep. Once you decide "I'm targeting 99.5% crash-free," the remaining 0.5% becomes a budget of failures you are allowed to spend. While budget remains, you keep shipping features. When you're burning through it fast, you act in proportion to that speed — the burn rate. Just by shifting what I was judging — from "the current value" to "the pace of consumption" — the wobble dropped dramatically.

Don't apply the same SLO to all 6 apps

My first mistake was setting the same "99.5% crash-free" target on all 6. It did not work. A single crash means something completely different on a flagship wallpaper app than on a small calming app doing a few thousand downloads a month.

Today I split the apps into 3 tiers along two axes — revenue contribution and DAU — and set a different SLO per tier.

  • Tier 1 (core, DAU in the tens of thousands): 99.5% crash-free (user-based) / ANR under 0.47%. Carries most of the AdMob revenue, so the strictest target
  • Tier 2 (growing, DAU in the thousands): 99.0% / ANR under 0.6%. Still being grown, so I balance quality against feature velocity
  • Tier 3 (mature, DAU in the hundreds to a thousand): 98.5%. Apps I've decided not to invest in further. Breaching the budget mostly means "observe"; breaching it repeatedly becomes input for a sunset decision

The key idea: an SLO is not a quota to hit, it's a tool for deciding where your time goes. When a Tier 3 app breaks its SLO I don't jump. Instead I read "Tier 3 keeps exhausting its budget" as a signal that it's no longer worth my hands, and feed that into the sunset call. The point of the SLO isn't perfect quality — it's mechanically deciding how to allocate finite time across 6 apps.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
How to assign different SLOs per app by revenue contribution and DAU, with a concrete 3-tier target table for a 6-app portfolio
A 90-line Cloudflare Workers implementation (copy-paste ready) that computes error-budget remaining and burn rate over a 28-day rolling window
A decision gate that mechanically separates freeze, hotfix, and sunset-review from budget consumption, plus how to handle noise on low-DAU apps
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

Dev Tools2026-05-27
Making Silent Failures Visible Across 6 Rork Apps: An Early-Warning Design Note for Non-Crash Degradation
Notes from running 6 wallpaper apps in parallel and the layer I built in 3 weeks to make Crashlytics-invisible failures observable. Beacons, timeouts, and a small Cloudflare Worker for cross-app aggregation.
Dev Tools2026-05-26
Aggregating App Store Connect, RevenueCat, and AdMob into One Morning Digest with Cloudflare Workers — A Six-App Indie Architecture
A practical architecture for indie developers running multiple Rork apps: aggregate App Store Connect API, RevenueCat REST, and AdMob Reporting API in a Cloudflare Workers Cron job and ship a single daily Slack digest each morning.
Dev Tools2026-05-21
Automating Production Incident Response as a Solo Developer — Crashlytics, Sentry, Slack Routing, and Staged Rollback
Twelve years of running my own iPhone and Android apps, accumulating 50 million downloads, taught me a specific shape for production incident response. This article shares the Crashlytics + Sentry double layer, Slack routing into interrupt and log channels, and a Remote Config plus EAS Update staged rollback I keep returning to.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →