Skip to main content
Version: 2.8

Architecture

The Meshtastic Android and Desktop apps follow a modular Kotlin Multiplatform (KMP) architecture with clear layer boundaries (iOS is currently a compile-only validation target — there is no shipping iOS app yet).

Layer Overview​

┌─────────────────────────────────────────────┐
│ androidApp / desktopApp │ Platform entry points
├─────────────────────────────────────────────┤
│ feature/* modules │ UI + Business Logic
├─────────────────────────────────────────────┤
│ core/* modules │ Shared infrastructure
├─────────────────────────────────────────────┤
│ Platform (Android/JVM/iOS) │ OS-specific bindings
└─────────────────────────────────────────────┘

Module Categories​

androidApp/ — Android Application​

The Android application entry point:

  • Activity, Application, and Manifest definitions
  • Koin DI module composition (AppKoinModule)
  • Flavor-specific bindings (google/, fdroid/)
  • Android-only integrations (widgets, services)

desktopApp/ — Desktop JVM Application​

The Desktop (Linux/macOS/Windows) entry point:

  • Compose Desktop window management
  • Desktop-specific DI (DesktopKoinModule)
  • Platform stubs for Android-only capabilities
  • BLEBLE (Bluetooth Low Energy). The default wireless connection between a node and a phone client. (Kable), Serial, and TCPTCP (Transmission Control Protocol). One of the three ways a client reaches a node, alongside serial and Bluetooth. Clients connect over TCP on port 4403. transport implementations

feature/* — Feature Modules​

Each feature/ module owns a vertical slice of functionality:

ModuleResponsibility
feature:introOnboarding/welcome flow
feature:messagingMessages, channels, contacts, quick chat
feature:connectionsBluetooth/USBUSB (Universal Serial Bus). The wired connection used to power a device, flash firmware onto it, and communicate with it over serial./TCPTCP (Transmission Control Protocol). One of the three ways a client reaches a node, alongside serial and Bluetooth. Clients connect over TCP on port 4403. connection management
feature:mapMap display, waypoints
feature:nodeNode list, node detail, metrics
feature:settingsAll configuration screens
feature:firmwareFirmware update flow
feature:docsIn-app documentation browser
feature:wifi-provisionWiFi provisioning
feature:widgetAndroid home screen widgets
feature:discoveryMesh network discovery
feature:carAndroid Auto / Car App Library — google flavor only, conditionally registered in the google FlavorModule

Feature modules:

  • Use the meshtastic.kmp.feature convention plugin
  • Depend on core modules, never on other feature modules
  • Own their navigation entries and DI registrations
  • Contain platform-specific implementations in androidMain/jvmMain/iosMain

core/* — Core Modules​

Shared infrastructure used by all features:

ModuleResponsibility
core:commonUtilities, extensions, build config
core:navigationRoutes, deep links, Navigation 3
core:uiShared Compose components, icons, theme
core:resourcesShared string resources
core:modelDomain models
core:dataData layer abstractions
core:domainUse cases / business logic
core:databaseRoom KMP database
core:datastoreDataStore preferences
core:prefsApp preferences
core:repositoryRepository interfaces
core:serviceMesh service layer
core:diDI utilities
core:networkHTTP/serial/transport
core:bleBluetooth LE abstractions
core:barcodeQRQRA scannable square code. In Meshtastic it encodes the Channel URL, which carries the channel and LoRa settings needed to join a mesh. / barcode scanning (channel-share QRQRA scannable square code. In Meshtastic it encodes the Channel URL, which carries the channel and LoRa settings needed to join a mesh. codes)
core:nfcNFCNFC (Near Field Communication). A very short-range wireless protocol. Some clients expose NFC-related settings. read/write support
core:takserverEmbedded TAKTAK (Team Awareness Kit). A situational awareness ecosystem. Meshtastic bridges to it by converting mesh messages to and from Cursor on Target format. server integration
core:testingTest utilities
core:konsistKonsist architecture/convention tests

ProtobufProtobuf (Protocol Buffers). A method developed by Google for serializing structured data, used in Meshtastic for efficient communication protocol between devices. models are no longer a local module — they come from the external org.meshtastic:protobufs Maven artifact (pinned in gradle/libs.versions.toml).

KMP Source Sets​

Each module uses the standard KMP source set hierarchy:

src/
├── commonMain/ ← Shared code (all platforms)
├── commonTest/ ← Shared tests
├── androidMain/ ← Android-specific
├── jvmMain/ ← Desktop JVM-specific
├── iosMain/ ← iOS-specific
└── jvmTest/ ← Desktop test host

Golden Rules:

  • No android.* imports in commonMain
  • Platform-specific code goes in appropriate source set
  • Prefer interfaces + DI over expect/actual for complex behaviors
  • Use expect/actual only for simple declarations

Dependency Injection​

The project uses Koin with annotation processing:

  • @Module, @Single, @Factory annotations
  • @ComponentScan for automatic registration
  • Feature modules export their own Feature*Module class
  • App/Desktop compose all modules in their root DI configuration

Radio Control​

Features issue radio commands through RadioController (core:repository), a composite of four focused sub-interfaces so callers can depend on just the slice they need:

Sub-interfaceResponsibility
AdminControllerConfig, channels, owner, device lifecycle, editSettings { } transactions
MessagingControllerSend packets, reactions, shared contacts
NodeControllerFavorite, ignore, mute, remove nodes
QueryControllerTelemetry, traceroute, position/user-info queries

RadioControllerImpl (core:service) is the in-process composition root for all targets (Desktop, iOS, single-process Android). It assembles the four sub-controllers via Kotlin interface delegation and adds the cross-cutting concerns (connection state, packet-id, location, device-address switching). Commands are direct suspend calls; admin writes are fire-and-forget because the device is the source of truth (local persistence is an optimistic cache). The layered shape mirrors the meshtastic-sdk AdminApi/TelemetryApi design to ease a future SDK migration.

Service Repository​

ServiceRepository is the reactive bridge between the mesh service and all feature/UI layers. It is decomposed into focused provider interfaces following the Interface Segregation Principle:

InterfaceResponsibility
ConnectionStateProviderRead-only connectionState: StateFlow<ConnectionState>
TracerouteResponseProviderTraceroute response state + clear
NeighborInfoResponseProviderNeighbor info response state + clear
ServiceStateWriterWrite-side for handlers (set*, emit*, clear*)

ServiceRepository extends all four interfaces — consumers inject the narrowest interface they actually need. For example, ContactsViewModel injects only ConnectionStateProvider rather than the entire ServiceRepository, preventing accidental access to write operations from UI code. RadioController also extends ConnectionStateProvider so VMs that already inject a controller sub-interface can read connection state without a separate dependency.

Navigation uses Navigation 3 with typed routes:

  • All routes defined in core/navigation/Routes.kt
  • Routes are @Serializable data classes/objects
  • Deep links resolved through DeepLinkRouter
  • Each feature registers its own navigation entries

See Navigation & Deep Links for details.