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 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
The rest of our cross-platform work
Shared-codebase engagements overlap more than most. These are the neighbouring ones.
Where we have built this
Sectors where the same product has to reach two audiences on two platforms.

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.

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.

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.

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.
Related work
Engagements where one product had to reach two platforms at once.
Questions about cross-platform work
The ones we are asked most often before a first conversation.
React Native or Flutter?
Will it be as fast as a native app?
What if we need something the framework does not support?
How much of the code is actually shared?
What happens when the framework releases a major version?
Can we get a web app from the same codebase?
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.

