DEV Community

Jefferson Silva
Jefferson Silva

Posted on

Webviews Aren't Slow. Your 'Native' Framework Is in Debt.

To be clear about the title up front: by 'native framework' I don't mean apps written directly against the platform APIs in Swift or Kotlin. Those have no translation layer, so there's no debt, they are the platform. I mean cross-platform frameworks that reach the platform through an abstraction, mapping your components to native widgets on your behalf. That layer is where the debt lives: you don't get a new platform feature until the abstraction gets around to wrapping it.

Every time someone ships an app in a webview, a native purist materializes in the replies to explain that it is not a real app. The engine is a decade past their objection, and the alternative they are defending signed a debt they never put on the invoice.

Let me make the case that will annoy both camps, then concede the one place the purists are actually right, because that concession is the whole point.

TL;DR

  • "It's just a webview, so it's slow" stopped being true around 2014. The engine is Safari and Chrome.
  • Performance was never the real argument anyway. The real argument is fidelity.
  • "Everything is native" is not a feature. It is a promise to cover 100% of the OS surface, forever, and 90% coverage is not 90% good.
  • A webview never makes that promise, so it never carries that debt. It renders what is yours and buys native deliberately, where it chooses.
  • If your app is in the 5% that is genuinely per-frame bound, go native and ignore all of this. If it is in the other 95%, the purist is defending a promise that breaks on their own users.

"It's just a webview" is nostalgia, not an argument

On iOS the webview is WKWebView, the same engine as Safari. On Android it is the Chromium-based System WebView, the same engine as Chrome. JIT-compiled JavaScript, GPU-composited layers, hardware-accelerated scroll and animation. It is, quite literally, the rendering engine a native app reaches for when it needs to render web content.

The "webviews are slow" reflex is a memory of the UIWebView era, before WKWebView, before Chromium ate Android. Somewhere a developer got burned in 2013 and has been repeating it at conferences ever since. For lists, forms, dashboards, content, commerce, the boring 95% of what apps actually are, the render is indistinguishable from native, because it is the same engine drawing the same pixels.

If your best argument against a webview is that it is slow, you do not have an argument. You have a grudge from the iPhone 5.

Where the purists are right (and I mean it)

Here is the concession, up front, because a provocation that hides its weak spot deserves the dunk it gets.

Some software is bound by exactly what a webview and a bridge are worst at: sustained per-frame computation. Real-time 3D and games. Low-latency audio. Computer vision on a live camera feed. Anything that has to do heavy work sixty or a hundred and twenty times a second with no room for a hop.

For that software the webview loses, the bridge loses, and no hybrid stack saves you. Not React Native, not Flutter, not Capacitor, not the thing I build. They all share that ceiling because it is the ceiling of the category. If your app lives above that line, write native and stop reading. You were always going to.

That is maybe five percent of apps. Now let us talk about the other ninety-five, and the argument the purists never actually make out loud.

The real debate was never speed. It was fidelity.

Nobody who is serious is worried that a webview cannot render a settings screen fast enough. The honest objection is fidelity: does it feel like the platform. Does the tab bar feel like iOS. Does the sheet slide like Material.

And the answer the industry reached for is component mapping: write your components once, and the framework translates each one into a native widget under the hood. React Native's whole pitch. It sounds like the best of both worlds.

It is also where the bill is hiding.

"Everything is native" is a debt, not a feature

The moment your framework promises "everything is native," it has signed up to deliver exactly that. In full. Not most of it.

And this is the part that should end the argument: ninety percent coverage is not ninety percent good. The missing ten percent does not disappear. It waits. Every user, eventually, reaches the one behavior the translation did not cover, the gesture that feels off, the edge case the mapping never wrapped, the OS update the abstraction has not caught up to. And when they hit it, the illusion of native breaks precisely at the point where being native was supposed to matter.

That is not a bug you fix once. The debt is the entire surface of the operating system, forever. Every OS release, the surface grows, and the mapping starts the race from behind again, because it can only ever wrap what it already knows about. You are perpetually paying interest on a promise you made to cover something that keeps expanding.

And there is a second floor below that one. You write your code believing you are writing native. You are not. You are writing to an abstraction that translates on your behalf, and the day your case falls outside the translation, you drop into a limbo where you end up writing the native code anyway, by hand, with a framework wedged in the middle. You took on the native maintenance burden and the abstraction, and got to skip neither.

"Everything is native" is total debt: the whole OS surface, forever. A webview is point debt: you pay native cash only where you decide to.

What a webview actually does with that trade

A webview does not make the promise, so it never carries the debt.

The part of the app that is yours, your UI, your screens, your design, renders identically everywhere on one consistent engine, because it was your design and it was always going to look the same on both platforms anyway. There is nothing to translate. Nothing to keep behind the OS. A product page is a product page.

And the part that genuinely has to feel like the platform, the chrome, the tab bar, the sheet, the transition, you deliver as real native, deliberately, for the specific behaviors you choose. Point debt. You pay native cash exactly where it buys fidelity, and nowhere else. Not a mapping table stretched across the entire OS in the hope that it covers every case your users will ever touch.

One approach makes everything a translation and prays the coverage holds. The other makes nothing a translation and spends native effort like a scalpel. Those are not the same risk profile, and pretending they are is how "everything is native" gets sold as a free lunch.

So pick your debt, honestly

This is not "webview instead of native." It is a choice about which debt you sign.

Choose component-mapping and you have promised the full OS surface, forever, and it will break on some of your users at the worst possible moment, on a feature you thought you had covered.

Choose a webview and you have promised nothing you cannot keep: consistent rendering for what is yours, real native for the handful of behaviors where it actually matters, and no illusion to shatter, because you never sold one.

If you are in the five percent, go native, and you have my blessing. If you are in the ninety-five, the person telling you a webview is not a real app is defending an architecture that quietly took on a debt yours never did, and calling you the one cutting corners.

Tell me where I am wrong. But "webviews are slow" is not where. That ship sailed with the iPhone 5, and half the apps in your pocket are already webviews you never noticed.


The reasoning behind every one of these calls is written up in the open, and the documentation is a live discussion, not a finished monument. If you want to argue a point, correct one, or see the trade-off spelled out in full: join the documentation discussions.

Top comments (0)