Skip to content
CipherCruCipherCru

Menu

Cross Platform App Development

Cross Platform App Development

A shared codebase is not a promise that nothing will be written twice. It is a decision about which things are worth writing twice, taken deliberately and early.

Typical duration
Five to twelve months
Team shape
Three to five senior engineers
Starts with
Drawing the shared/native line
The same application running side by side on two different handsets

The boundary is the architecture

Every cross-platform project has a line: on one side, the code both platforms share; on the other, the parts written natively because the shared layer cannot reach them well. Where that line sits determines the cost of the next three years.

Teams that draw it in week one ship a maintainable product. Teams that discover it feature by feature end up with a shared codebase full of platform conditionals, which is the worst of both arrangements — two behaviours to test and one place to break them. We draw the line in the diagnostic, write it down, and treat moving it as a decision rather than a workaround.

What usually goes wrong, and what we do instead

The pattern is consistent enough that we now spend the first fortnight on the boundary.

Where shared codebases go wrong

  • Platform conditionals scattered through shared code until nothing is shared
  • A native module written by whoever was free, and understood by nobody
  • Framework upgrades deferred until the version is unsupported
  • Both stores' release processes discovered separately and late
  • Performance judged on a flagship, then met on a three-year-old handset

How we build it instead

  • The shared and native boundary drawn and written down before any code
  • Native modules owned, documented, and tested like the rest of the app
  • Framework upgrades treated as routine maintenance, not as a project
  • One release pipeline covering both stores, built in the first month
  • Performance budgets measured on the slowest device you support

What we build

The parts of a shared codebase that decide whether it stays shared.

Boundary design

What is shared, what is native, and the rule for deciding — written down before the first feature.

Shared application code

React Native or Flutter, with navigation and state that respect each platform's conventions.

Native modules

The hardware and platform surfaces the shared layer cannot reach, owned and tested rather than borrowed.

Offline and sync

One sync contract implemented once, which is the main saving a shared codebase actually delivers.

Performance budgets

Startup, frame rate and memory measured on the slowest supported device, enforced in CI.

Dual release pipeline

One build process producing both store artefacts, with staged rollout and a way to halt it.

What you end up with

Stated from your side rather than ours.

  • One team rather than two

    A feature is specified once, built once and tested once, which is where the saving actually comes from.

  • Two apps that behave the same

    One sync contract and one set of business rules mean a bug is in one place rather than being two different bugs.

  • A boundary you can point at

    What is shared and what is native is documented, so the next engineer does not have to infer it from the code.

  • Releases that do not diverge

    One pipeline produces both store artefacts, so the two platforms cannot quietly drift onto different versions.

How the build runs

The same five stages as every engagement, applied to a shared codebase.

Diagnose

What the app must reach on each device, who will maintain it, and where the shared and native line should sit.

Decide

The framework, the boundary and the performance budgets, written down with what each one costs.

Prove

One workflow shipped to both stores from one pipeline, on the slowest supported device.

Deliver

Features built in slices, each released to both test tracks before the next is scoped.

Hand over

Your team ships a release to both stores with us watching, then without us.

What we build it with

Chosen for what a shared codebase has to survive across two platforms.

Shared

  • React Native
  • Flutter
  • TypeScript
  • Expo

Native

  • Kotlin
  • Swift
  • Jetpack Compose
  • SwiftUI

Data and services

  • SQLite
  • Firebase
  • PostgreSQL
  • Node.js
  • GraphQL

Delivery

  • GitHub Actions
  • Gradle
  • TestFlight
  • Sentry

What you get, and when

Handed over as it is produced, not assembled at the end.

  • The shared and native boundary, written down with its reasoning
  • The framework choice, and what it rules out
  • Performance budgets tied to the slowest supported device
  • Source in repositories you own
  • One pipeline producing both store artefacts
  • Native modules documented and tested like the rest of the code
  • Store declarations matching what the app collects, on both
  • Crash and performance dashboards split by platform
  • A release runbook your team has used with us on both stores

Where we have built this

Sectors where the same product has to reach two audiences on two platforms.

A cafe table by an airport window with a laptop open on a travel booking screen showing destinations and dining, a passport, a boarding pass and a phone beside it

Food & Travel

Digital experiences that keep customers and operations moving.

We build customer journeys and operational platforms around ordering, booking, marketplaces, partner integrations, administration, and real-time workflows where experience and operational efficiency need to work together.

A gym floor with a phone showing the day's activity - steps against a goal, calories, distance and heart rate - beside a watch tracking a run in progress

Fitness

Digital products designed to turn engagement into progress.

We create fitness platforms supporting member experiences, scheduling, subscriptions, progress tracking, coaching workflows, administration, and integrations, with usability and continued engagement at the centre.

An open-plan office with a laptop showing a workforce dashboard - headcount, attendance, leave requests and approvals - and the same modules on a phone

HRMS

Workforce systems built around how organisations actually operate.

We build and improve workforce platforms spanning recruitment, onboarding, employee management, attendance, operational workflows, reporting, and integrations, reducing friction across the employee lifecycle.

A lecture room seen from the back, a laptop in the foreground playing a course video beside its numbered module list, the same course open on a phone

EdTech & eLearning

Learning platforms designed around engagement and scale.

From learner journeys and course delivery to assessments, administration, analytics, and integrations, we develop education platforms that make learning experiences easier to operate, evolve, and scale.

Questions about cross-platform work

The ones we are asked most often before a first conversation.

React Native or Flutter?
Usually React Native if your team already writes TypeScript, because the app then lives inside a skill set you already hire for. Usually Flutter if the interface has to look and behave identically everywhere and you want the web from the same codebase. Both are mature and both ship serious products; the deciding factor is almost always who maintains it afterwards rather than a benchmark.
Will it be as fast as a native app?
For most applications the difference is not perceptible, and for a few it is decisive. Heavy custom animation, sustained camera or sensor processing, and complex list rendering on low-end hardware are where a shared codebase costs you. We establish which of those your app does during the diagnostic, and if the answer is that it does several, we will recommend native rather than take the work.
What if we need something the framework does not support?
You write a native module, which is normal and planned for rather than a failure of the approach. What matters is that it is owned — documented, tested and maintained like any other part of the codebase — instead of being a piece of Swift somebody added under time pressure that nobody else can change. The boundary document says what is expected to live there.
How much of the code is actually shared?
It depends entirely on the app, and any general percentage would be marketing rather than an answer. What is reliably shared is the part that matters most for cost: business rules, the sync contract, the data layer and the majority of screens. What is reliably not shared is deep platform integration. The diagnostic tells you where your app sits before you commit.
What happens when the framework releases a major version?
It is routine maintenance, and it needs to be treated that way from the start. Both frameworks move quickly, and a codebase two major versions behind gets progressively harder to update while the security fixes only land on current versions. We set the upgrade cadence during the engagement and leave you on a version that is straightforward to move from.
Can we get a web app from the same codebase?
Sometimes, with real caveats. Flutter compiles to the web, and React Native has React Native Web, and both can work well for an app-like interface. Neither is a good route to a content site or anything that needs to be indexed, and the interaction expectations on a desktop browser differ enough that shared screens often need work. We would rather tell you which parts genuinely transfer than sell the whole idea.

One product, two stores?

Tell us what the app has to reach on the device. We will tell you where the shared and native line should sit.

Strictly necessaryEssential for the site to function: page navigation, security, session management, and remembering the cookie choices you make here.
Always on
FunctionalRemembers choices you make, such as language, region or display preferences, so the site opens the way you left it.
Performance and analyticsPerformance and analytics cookies show us how the Website is used: which pages are visited, how long is spent on them, where visitors came from, and what errors occur. They are set by Google Analytics and by HubSpot, whose cookies also link the pages you viewed to any enquiry you later send us.
Marketing and targetingTracks browsing activity to measure advertising and show relevant ads. We set none of these today, and will not without your opt-in.