Learn how to share business logic across Android, iOS, and other platforms using Kotlin Multiplatform while keeping native UI and capabilities where they matter.

Kotlin Multiplatform (KMP) has matured into a practical architecture for teams that want to share business logic across Android, iOS, and other platforms while keeping platform-specific UI and capabilities where they matter. The real challenge is not deciding how much code to share—it is designing boundaries that maximize reuse without turning every platform into the same application.
Building applications for multiple platforms traditionally means maintaining separate codebases.
For example:
Android
↓
Kotlin
iOS
↓
SwiftThat gives each platform maximum flexibility, but it can also create duplicated business logic.
The same rules may need to be implemented twice:
Authentication
Networking
Validation
Data models
Caching
Synchronization
Business rules
Over time, the implementations can drift.
One platform may receive a bug fix while another does not.
Kotlin Multiplatform offers another approach:
Shared Kotlin
│
┌──────────┴──────────┐
▼ ▼
Android iOS
│ │
Native UI Native UIThe goal is not necessarily to share everything.
It is to share the parts that benefit from being implemented once.
KMP is most powerful when code sharing follows architectural boundaries rather than forcing platforms into identical implementations.
Kotlin Multiplatform allows Kotlin code to target multiple platforms.
A shared module might contain:
shared/
├── domain/
├── data/
├── networking/
├── models/
└── validation/Meanwhile, platform applications can contain:
Android
├── UI
└── Android Integrations
iOS
├── UI
└── Apple IntegrationsThis creates a useful separation.
Owns:
Business rules
Models
Networking
Persistence abstractions
Validation
Use cases
Owns:
Native UI
Platform APIs
Device integrations
Platform-specific behavior
This architecture lets teams reuse logic without eliminating native platform capabilities.
A strong KMP architecture often follows a layered model:
Presentation
/ \
Android iOS
│ │
└──────┬─────────┘
▼
Domain
│
▼
Data
│
┌────────┼────────┐
▼ ▼ ▼
Network Storage ServicesThe shared domain should not depend on Android or iOS UI frameworks.
For example:
Domain
├── User
├── Order
├── Checkout
└── AuthenticationThe UI consumes the domain rather than owning the business rules itself.
This makes shared code easier to test and reuse.
One of the most important KMP decisions is deciding what not to share.
A good candidate for sharing:
CalculateOrderTotal()
ValidateEmail()
LoadUserProfile()
SubmitPayment()A questionable candidate:
Complex Native UI
Platform Navigation
Platform Animation
Platform-Specific InteractionThe question should not be:
"Can we share this?"
Instead ask:
"Should we share this?"
A useful rule is:
Business Logic
↓
Usually Shared
Platform Experience
↓
Often NativeThis allows iOS and Android teams to build experiences that feel natural on their respective platforms.
Sometimes shared code needs a platform-specific implementation.
For example, imagine the application needs a secure device identifier.
The shared code can define the expected capability:
expect class DeviceInfo {
fun identifier(): String
}Each platform provides its own implementation.
Conceptually:
Shared API
│
expect
/ \
/ \
Android iOS
actual actualThis creates a controlled boundary between shared logic and platform-specific capabilities.
The important principle is to keep these boundaries small.
If the shared module constantly asks the platform layer for dozens of tiny implementation details, the architecture can become difficult to understand.
Networking is one of the strongest candidates for shared KMP code.
A typical architecture might look like:
Repository
│
▼
API Client
│
┌────────┴────────┐
▼ ▼
Server Local CacheShared code can handle:
API models
Serialization
HTTP communication
Error mapping
Repository logic
Caching rules
For persistence, teams can define shared abstractions while allowing platform-appropriate implementations.
For example:
Shared Repository
│
▼
Storage Interface
/ \
/ \
Android iOS
Storage StorageThis keeps business logic independent from the underlying storage mechanism.
Kotlin Multiplatform does not require teams to share UI.
You can use:
Shared Kotlin
│
┌───┴────┐
▼ ▼
Android iOS
│ │
Compose SwiftUIThis is often attractive when teams want highly native platform experiences.
Alternatively, Compose Multiplatform can allow UI code to be shared across supported platforms.
That architecture can look like:
Shared
┌───────────────┐
│ Logic + UI │
└───────┬───────┘
│
┌───────┴───────┐
▼ ▼
Android iOSThe decision should depend on the product.
Share UI when:
Visual consistency is important
Teams want a common UI implementation
The interaction model is similar across platforms
Keep UI native when:
Platform conventions matter heavily
The experiences differ substantially
Teams need maximum platform-specific flexibility
There is no requirement to choose one extreme.
A hybrid architecture can be very effective.
A KMP project can become complicated if dependency boundaries are unclear.
A scalable structure might look like:
project/
├── shared/
│ ├── domain/
│ ├── data/
│ └── core/
│
├── androidApp/
│
└── iosApp/For larger organizations, shared modules can be split further:
shared/
├── authentication/
├── networking/
├── payments/
├── profile/
└── analytics/But modularization should have a purpose.
Too few modules create large, tightly coupled components.
Too many modules create unnecessary build and dependency complexity.
A good module should have:
Clear ownership
A clear API
A clear responsibility
One of KMP's biggest advantages is that business logic can be tested once.
For example:
Shared Business Rules
↓
Unit Tests
↓
Android + iOSTest areas such as:
Validation
Authentication logic
Data transformation
Repository behavior
Business rules
Error handling
Platform-specific code should still have platform-specific tests.
A good testing model is:
Shared Logic
↓
Shared Tests
Android Integration
↓
Android Tests
iOS Integration
↓
iOS TestsThe objective is not to eliminate platform testing.
It is to avoid testing identical business logic separately on every platform.
Sharing code does not automatically mean better performance.
KMP applications still need to be evaluated according to platform-specific runtime behavior.
Important areas include:
Startup time
Memory usage
Network performance
Serialization
Database operations
Concurrency
Binary size
For example, sharing a large dependency simply because it works across platforms can increase application size unnecessarily.
A good architecture asks:
Does sharing this capability actually reduce total complexity and cost?
Measure the result.
Do not assume.
More shared code does not automatically mean a better architecture.
They have different conventions, capabilities, and user expectations.
Business logic should remain independent from presentation.
A huge shared module eventually becomes difficult for multiple teams to own.
Too many `expect`/`actual` boundaries can indicate that abstractions are not well designed.
Do not avoid excellent platform APIs simply because they are not cross-platform.
Compose Multiplatform can be powerful, but UI sharing should follow product needs.
Platform integrations still need real platform testing.
Find functionality currently implemented independently on Android and iOS.
Look for:
Networking
Models
Validation
Authentication
Business rules
For example:
Existing Android
Existing iOS
↓
Share Networking
↓
Validate ArchitectureAvoid rewriting the entire application immediately.
Decide what belongs in:
Domain
Data
Platform
UI
Prove that the shared business layer behaves consistently.
Keep device-specific functionality behind explicit interfaces.
Do not assume shared business logic requires shared UI.
Track:
Code reuse
Feature delivery time
Defect rates
Build times
App performance
Team productivity
Once the architecture proves itself, move additional domains into shared modules.
Networking
↓
Authentication
↓
Domain
↓
Persistence
↓
Additional FeaturesKMP is part of a broader shift toward shared business capabilities with platform-specific experiences.
A mature architecture can look like:
Product
│
Shared Domain
│
┌────────────┼────────────┐
▼ ▼ ▼
Android iOS Other
│ │ │
Native / Native / Platform
Shared UI Shared UI UIThis model gives teams several options.
They can share:
Core logic
Networking
Persistence
Models
Analytics
Design-system components
and keep specialized capabilities native.
AI-powered applications, offline-first products, financial applications, and connected-device experiences can particularly benefit from shared domain logic because consistency across platforms becomes increasingly important.
The bigger opportunity is architectural:
One business model, multiple excellent platform experiences.
Engineering leaders considering Kotlin Multiplatform should ask:
Which logic is duplicated across platforms today?
Which parts genuinely benefit from one implementation?
Where do Android and iOS need different experiences?
How much platform-specific code will remain?
Who owns the shared modules?
How will shared dependencies be governed?
Will UI also be shared, or only business logic?
How will the team test platform integrations?Most importantly:
Are we adopting KMP to solve a real architectural problem, or simply because code sharing sounds attractive?
Kotlin Multiplatform is most effective when it creates the right balance:
Shared Logic
│
┌──────────────┼──────────────┐
▼ ▼ ▼
Networking Domain Storage
│ │ │
└──────────────┼──────────────┘
│
┌────────┴────────┐
▼ ▼
Android iOS
│ │
Native / Shared Native / Shared
UI UIShare what should be consistent.
Keep platform-specific capabilities where they provide real value.
Define clean module boundaries.
Test shared logic once and platform integrations where they actually run.
Avoid turning the shared layer into a massive dependency that every team must understand.
And remember that successful multiplatform architecture is not measured by the percentage of code shared.
The goal is not maximum code reuse. The goal is maximum engineering leverage without sacrificing product quality.
Kotlin Multiplatform gives teams the flexibility to build one shared foundation while still respecting what makes Android and iOS different.
Share the logic that benefits from consistency. Keep the experiences that benefit from being native. Build clear boundaries. And let architecture—not ideology—decide what should be shared.
We build custom software, mobile apps, and web platforms for startups and enterprises.



Their team became an extension of ours — within months they'd rebuilt our entire product experience from the ground up.
