メンバーシップ
Advanced guides with production-ready code
Thank you for visiting Rork Lab. We publish advanced guides daily with copy-paste ready code, benchmarks, and production design patterns — practical content we hope you'll find useful as the next step after our free articles.
- ✦Unlimited access to all premium articles
- ✦New advanced guides with code published daily
- ✦Production-ready design patterns & best practices
Premium Articles
499 exclusive articlesAn Image Requested Once Before Its Upload Stayed a 404 at the Edge. I Split the Retention Rules by Status Code and Made Upload and Purge a Single Step
A new wallpaper stayed missing in some regions because the CDN kept a 404, fetched once before the upload, as long as it kept the image itself. Per-status retention, a two-request diagnosis, and pairing upload with purge, tested in Node.
Users Told Me They Could Not Close a Fullscreen Ad. The Entry Points Were Scattered, So I Put the Show-or-Not Check and a Safety Net in One Place
An unclosable fullscreen ad came from calls that ignored foreground state, a clash with a permission dialog, and no safety net. A single entry-point component, tested in Node.
Remembering What the AI Decided: Four Marks in the Cache Key Paid Off on Model-Swap Day
A small on-device cache for AI answers, with the model name and prompt version in the key so old answers vanish on swap day. TypeScript plus simulated results.
Your 5% Rollout Says 99.76% Crash-Free. How Many Users Until You Can Trust It?
At 5% rollout, a crash-free rate rests on few users and the interval is wide. A Wilson-interval script that says proceed, wait or halt, plus simulated numbers on how often you halt a good release.
Fullscreen Ads Stopped Showing After Going Back and Forth Between Screens — The Ad Holder Was Still Holding a Closed Screen
Fullscreen ads vanished after reopening a screen because a reused ad holder kept notifying a closed screen. A holder that swaps only its listener target, tested in Node.
The ANR Was Coming From Cleanup When a Screen Closed: Classifying the Blocking Line From Traces
A Python script that reads Android ANR traces and classifies the line that blocked the main thread, such as billing client teardown or synchronous image decoding. Two causes I found in my wallpaper apps, and the thinking behind the fixes.
Store Sales CSVs Come in Different Shapes: Reduce Them to Four Columns, Fix the Month-End Rate, and Keep the Raw Totals
A small Python script that reduces App Store and Google Play sales CSVs to four columns (date, app, amount, currency) and totals them by month and app. It never drops unreadable rows silently, fixes one exchange rate per month, and prints raw per-currency totals so you can reconcile.
My Launch Counter Went Up by Two on Every Launch — Why New Users' Ad-Free Grace Ended Early
New users' ad-free grace ended early because two callers each advanced the launch counter. A counter that moves once per launch, tested in Node.
Why Redeploying Doesn't Fix the Application Error You See Right After a Deploy
Right after I swapped a secret, every page showed Application error. Stale HTML was calling a JS file that no longer existed. Here are a detection script, a build-version check for the edge cache, and a once-only auto-reload, all run and verified.
One Missing Tutorial Image Was Enough to Stop the Whole App from Launching. Moving Nice-to-Have Features Off the Required Startup Path
On some devices the app never launched at all. The cause was a design where a missing tutorial image failed the whole screen build. A small wrapper that takes optional features off the startup path, and a pre-release check.
It Ran Fine in Debug, but the Release Build Died on Launch with a Resource Not Found. A File I Looked Up by Name Had Been Shrunk Away
A release-only crash at launch, caused by images and sounds looked up by a name string being removed by resource shrinking. A keep.xml written at prebuild, plus a post-build check that confirms it worked.
Before Moving to Expo SDK 58, List What Disappears in Your Own Code
A small audit script that scans your project for the APIs Expo SDK 58 removes, changes, or deprecates, with the output from a test project and the pitfalls I only noticed once I ran it.
301 or Internal Rewrite for Wallpaper Resolution Routing? Inside One Host, I Chose the Route That Doesn't Change the URL
When one host picks an image resolution for you, should it answer with a 301 or rewrite internally? I ran both on nginx and compared round trips, rule-order traps, and a small verification script.
My Ads Never Came Back After a Subscription Expired: Fixing the Direction of an Ad-Free Check
An ad-free flag stayed on after the subscription expired because the check pointed the wrong way. Here is how I rebuilt it to wait for two purchase queries, decide only from confirmed facts, and keep the last value on failure.
My App Open Ad Only Showed When the App Came Back From Background. The 'Returned to Foreground' Signal Fired Before the Ad Had Loaded
On a cold start, the app open ad in my Android app never showed. The foreground signal came before the load began. Here is how I split the signal from the load and rebuilt it as logic you can test ordering by ordering.
Take the Prompt Out of the App: An Edge Function Gateway With the Guard on the Output Side
A system prompt shipped inside your app is readable from the day it ships. This walkthrough moves the prompt into a Supabase Edge Function, lets the client name only a task, and puts the guard on an output allowlist, with tested code.
Multiseat Purchases Are Already On: Decide Whether to Keep Them Before October 22
Multiseat purchases for subscriptions have been on by default in App Store Connect since September 16. Before Volume Purchasing starts on October 22, here is how an indie developer can decide, in four questions, whether to keep them.
Your Expo Router App Flashes the Sign-In Screen on Every Launch. Rebuild the Guard With a Third State: Not Known Yet
Signed in, yet the sign-in screen flashes at launch; signed out, yet the screen never changes. How I rebuilt Expo Router Protected routes around three Supabase auth states, including the one the docs never name, and where the _layout.tsx files have to live.
A successful payment never tells you what to unlock. Routing four products through one Checkout
Tips, single articles, monthly plans and lifetime access all came back from Stripe looking identical. Here is how I moved entitlement off the amount and onto metadata, and why I now fail closed when the entitlement store goes quiet.
The recommended replacement was already gone — auditing all 74 rows of Gemini's deprecation table
Cross-checking Gemini's deprecation table turned up five rows where the recommended replacement had itself already shut down, including gemini-2.5-flash-image, which goes away on October 2. Here is how to verify a migration target, and how to catch the 404 before your users do.
Where the AI decision lives once Rork splits your app into two native codebases
New Rork apps are Swift on iPhone and Kotlin on Android — two separate codebases. Here is how I decide which AI-related judgments stay in each client and which move to the shared backend, plus the minimal contract both clients read the same way.
Your First EAS Workflow in a Rork Repo, and the Alert That Goes Missing Exactly When You Need It
Putting two files into .eas/workflows in a repo exported from Rork, and why a notification wired with needs stays silent on exactly the nights it fails — with the output of a small local checker I actually ran.
Whether You Need Rork Max Is Answered by Your Permissions, Not the Price Page
When I cannot decide between standard Rork and Rork Max, I stop reading the price page. Instead I pull every OS capability my app actually asks for out of app.json and Info.plist, then sort them into what Expo covers, what a config plugin covers, and what truly needs native Swift.
Sending user text to an external AI: what actually goes in Play's Data safety form
Classifying user input sent to an external AI as collected, shared, or ephemeral in Play's Data safety form, plus a redaction ordering bug found by running the code.
Your Blended eCPM Dropped and Revenue Went Up: Splitting the Change Into Country Mix and Rate
Blended eCPM is a weighted average, not a price. Here is how I split a month-over-month change into a country-mix effect and a rate effect that reconcile exactly to the total, plus what to check before you cut a low-eCPM country.
Your Widget Extension Can Submit a BGTaskScheduler Request. It Just Cannot Register the Handler
Calling BGTaskScheduler from a widget extension compiles, submits, and returns true — and then nothing runs. Here is why registration belongs to the host app only, and how I moved refresh ownership back where it belongs across my wallpaper apps.
EAS secret visibility does not keep a value out of your app — deciding prefix and visibility separately
The EXPO_PUBLIC_ prefix decides what ships inside your app; EAS visibility decides who can read it. Why stacking them blanks a value on OTA updates, and how to check your build.
My Second App From the Same Codebase Ships With a Distinct-Value Manifest
Google Play has drawn a clearer line around low-value apps. Here is how I decide where the distinct value of a sibling app lives, and the small script I run before every submission to check that the two apps have actually diverged.
I counted how many versions expo install starts recommending after one patch bump
What expo install recommends is tied to the patch version of expo itself. I measured the ledger diff against the npm registry, how far npm install drifts, and the one check worth adding to a generated project.
Adding image paste with expo-paste-input, and moving the disappearing file:// URIs out of cache
How to let users paste images and GIFs into a chat input with expo-paste-input. The URIs that onPaste hands you are temporary files that can vanish before the user hits send. Here is the relocation code and the order I verify it on real devices.