Skip to content
All articles
Mobile

Native app, hybrid or web: decide how much platform you want to carry

Andrey Gershengoren · · 8 min

"We need an app." That is how almost every conversation starts, and in most cases the sentence means something else: we need to be within the user's reach. An app in the store is one of several ways to be within reach, and the more expensive way is not automatically the right one. I have worked on native iOS apps for over ten years and still did not build my own product as an iOS app.

The scale from web app to native app

Between the browser and native code lies a scale. It sorts by how much platform you carry yourself: who delivers the application, what is shared between iOS and Android, and how much code your team owns for good.

  1. Web app or PWA. One codebase, delivered by the browser, installable on the home screen. No store, no review, updates land immediately. Device access only as far as the browser allows.
  2. Mini app inside a platform. The same web application, except it runs inside Telegram, WeChat or a comparable environment. The platform brings the users and sets the rules in return.
  3. WebView shell. Capacitor or Ionic wrap the web code into a store app. There is an icon in the store and native bridges for individual features; the rest stays web.
  4. UI drawn by the framework. React Native and Flutter share interface and logic and render on their own. Between your code and the operating system sits a bridge that someone has to maintain.
  5. Shared logic, native interface. Kotlin Multiplatform shares data models, the network layer and business rules. The interface is built natively on each platform, with SwiftUI and with Jetpack Compose.
  6. Native. Two codebases, two teams or one team with both skills, full access to everything the device can do.

None of the steps is better than another. Each is right for a particular answer to three questions.

Question 1: Where is the user already?

Installing an app is a hurdle. Open the store, search, download, create an account, confirm permissions. Each of these steps costs users, and among people who are not looking for your product anyway, it costs most of them. If the audience is already gathered in one place, it is worth asking whether to go there instead of pulling them out.

That was the starting point for CognitEase, my own product: a practice assistant for psychologists and therapists that turns session recordings into documentation and handles appointments, payments and video calls. Many in the target group already work in Telegram. An app of its own would have required them to learn one more platform.

So I built CognitEase as a web application, a Next.js frontend with a NestJS backend, and shipped it as a Telegram mini app. No installation, no store process, the users are already there. The messenger is only the first shell. The same application runs in the browser, and if an audience sits somewhere else, it gets another shell there without the product being rebuilt. That mobility is the real advantage of the web step, and for me as an iOS developer it was the stronger argument.

The price of this decision is the frame each shell sets. Inside Telegram, Telegram decides what a mini app may do, how it opens and how it looks. Notifications go through the bot rather than system push, and there is no secure on-device storage like the native keychain. CognitEase cannot be found in the app stores. These costs were known and are smaller than the hurdle an installation would have meant for this audience.

Question 2: How deep do you need to go into the device?

The second question pushes the decision the other way. Some requirements can only be met with native code, or only reliably there: NFC, biometric approval, key material in the Secure Enclave, certificate-bound connections, background processes the system must not kill at will. Each of them pulls the line on the scale downwards.

In a project in a heavily regulated healthcare environment the subject was authentication and security: OpenID Connect, FIDO, mutual TLS, certificate pinning, keys in the keychain, plus reading a health card over NFC. None of these requirements can be delegated to a browser or a framework bridge without the security argument developing gaps. That layer stayed native.

But native applied only to that layer. Above the security layer sat logic that had to be identical on iOS and Android. The card reading ran through a Kotlin Multiplatform module shared by both platforms; data models and the network layer likewise. The interface stayed in SwiftUI on iOS, and the interop with the existing Swift code was part of the work. That is step five of the scale, chosen deliberately, because step six would have meant doing this logic twice for no gain.

The price here is two toolchains in one project. A Kotlin build, a Swift build, testing in both worlds, an interop boundary that demands discipline. For a team that serves both platforms anyway, that is bearable. For a team with a single iOS developer it would add a second codebase to look after rather than take work away.

Question 3: How much platform code do you want to own?

The third question concerns the team after launch. Code that belongs to you has to be understood, updated and checked against every new iOS and Android release by someone. The scale is therefore also a scale of running costs.

At the top end you own web code and nothing else. At the bottom end you own two complete platform codebases. In between lies the question of who maintains the bridge. With React Native and Flutter the bridge is the framework itself; it solves the problem of the duplicated interface, but demands that someone on the team understands the bridge when a native module is missing or an OS update changes the rendering. I have not worked with React Native or Flutter in production. I know the mechanics of the bridge, not its running costs first hand, and I judge this step from the outside for that reason.

In practice the question reads: how many platforms can your team still seriously serve in two years? One, two or none? The answer often sorts the choice more clearly than any feature list.

The wrong shortcut

The most common mistake I see is choosing by what the existing team happens to know. A web team builds a WebView shell although the requirements reach into the device. An iOS team builds native although the users sit in a messenger and do not want an installation. Both work at first and get rebuilt two years later, this time with users, data and deadlines behind them.

The three questions can be answered before a single line of code exists, and they can be checked from the outside. Whoever recommends a step should be able to say which answer to which question led them there.

Limits

The scale helps with the choice, not with the execution. Two things it does not solve.

It says nothing about quality within a step. A badly built native app loses to a well-built PWA, and the other way round. And it applies to products whose requirements are known. For an early product that is still looking for its market, the answer to all three questions is provisional. Then you choose the step that penalises a change the least, and that is usually the one with the least platform code of your own.

Closing

The question "native or hybrid" leaves out the steps where the answer often lies: in the browser, in a platform where the users already are, or in shared logic under a native interface. Where is the user already, how deep do you need to go into the device, how much code do you want to own. I put these three questions in the intro call before any discussion of frameworks.

architectureKotlin MultiplatformPWAmini appdecision
Contact

First conversation: 30 minutes, free of charge, no presentation.

You describe the situation, I tell you whether and how I can help. No slides, no sales pitch.