◉ANTIGRAVITY LABJP
Articles/App Development
▣ App Development/2026-06-14Intermediate

How Far Can On-Device Inference Stay Free? Measuring the Line Between Foundation Models and Gemini

WWDC 2026 widened Apple Foundation Models' free tier, making on-device inference easier to reach for. But 'free, so everything on-device' hits cases where quality falls short. Here is how to decide the range you hold on-device and the range you pass to cloud Gemini by measurement, not guesswork.

Apple Foundation Models4iOS 274on-device inferenceGemini9fallback4cost management5indie development26measurement8

✦ Premium Article

After WWDC 2026, I tried shifting a small app's summarization feature onto on-device inference. The free tier had widened, so I wondered whether I could move what I'd been paying the cloud for onto the device.

Summarizing short text completed on-device surprisingly cleanly. But when I handed it long text laced with jargon, or text where several topics tangled together, the summaries increasingly skimmed the surface and missed the core.

The initial hope of "free, so everything on-device" breaks down right here. Yet reverting to "quality feels risky, so everything to the cloud" means not using the free tier that just widened, paying a network round trip even for a short summary.

Here, too, the answer is where to draw the line: how far to hold on-device, and from where to pass to the cloud. And drawn by feel, this line always leans too far one way. It's a line to draw by measurement.

See the dividing line with three rulers

Whether to use on-device or cloud can't be decided on a single criterion. I learned to look along three separate axes.

The first is quality: is the on-device model's output good enough to be usable for that task? This part is hard to put a number on, but the comparison I'll touch on later lets you build a proxy metric.

The second is latency. It may surprise you, but for short tasks on-device is often faster. With no network round trip, the first character returns sooner. Conversely, for long generation, the device's processing power tops out and the cloud can be faster. The intuition that matters is that it flips with task length.

The third is cost. On-device is effectively zero within the free tier. The cloud accumulates with every call. But making "free" the top priority while sacrificing quality drives users away and costs more in the end. Cost is an axis to view paired with quality, not alone.

Measure these three properly, once, against your app's representative requests, and the dividing line — "this kind of task is fine on-device," "this kind is better passed to the cloud" — becomes visible with grounding rather than guesswork.

Measure it once, in your own app

The three axes click into place faster after one measurement than after any amount of thinking. No elaborate benchmarking needed. Prepare about ten representative requests, feed the same input to both on-device and cloud, and just record the processing time and output side by side.

// A one-off measurement that records latency and output for both paths
func benchmark(_ inputs: [String]) async {
    for text in inputs {
        let t0 = Date()
        let local = try? await onDevice.summarize(text)
        let localMs = Date().timeIntervalSince(t0) * 1000
 
        let t1 = Date()
        let cloud = try? await cloudFallback.summarize(text)
        let cloudMs = Date().timeIntervalSince(t1) * 1000
 
        let faster = localMs < cloudMs ? "on-device" : "cloud"
        print(String(format: "len=%4d on-device=%.0fms cloud=%.0fms faster=%@",
                     text.count, localMs, cloudMs, faster))
    }
}

When I ran this in my app, on-device was consistently faster while inputs were short, and cloud overtook it somewhere past roughly 800 characters. For quality, reading the ten outputs side by side and marking the on-device ones that missed the core is enough to sense from what length it gets shaky.

You run this measurement once before drawing the line, not every time. Keeping the numbers at hand turns later threshold tuning from a vague feeling into something grounded.

✦

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
✦A decision procedure that measures the line between on-device and cloud inference on three points: quality, latency, and cost
✦A confidence-based fallback implementation that sends only the requests on-device inference can't answer to Gemini
✦An aggregation script for reviewing afterward how much of your traffic the free tier actually covered
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

Antigravity 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

▣ App Dev2026-08-19
Turn Off the Liquid Glass Compatibility Flag Yourself, Before Xcode 27 Does It for You
UIDesignRequiresCompatibility is expected to be ignored in Xcode 27. Flip it to false yourself and you can rehearse next year's forced appearance today, on the SDK you already have. Here is what actually broke in my wallpaper apps, and the order I checked things in.
▣ App Dev2026-10-28
I Fetched All 155 Sitemap URLs. Every One Returned 200, but 93% of the lastmod Dates Were the Same Day
A record of fetching every sitemap URL and cross-checking status, canonical, hreflang and lastmod. Full standard-library Python scripts and the mismatch I found.
▣ App Dev2026-10-20
I Edited a Sentence and Only the New Characters Turned into Tofu: Adding a Missing-Glyph Check to a Subsetted Japanese Web Font
Change one line of Japanese copy and the newly added characters can render as tofu boxes. Here is a small script that lists every character missing from a subsetted font, with file and line number, and fails the build if even one is absent, with real output from running it.