This is a ready-to-go Offline First Compose Multiplatform starter kit built to help you spin up full-stack apps fast. It bundles a Compose Multiplatform frontend for Android, iOS, Desktop, and Web right alongside a built-in Ktor backend. Everything is pre-wired so you can skip the boilerplate and go straight to shipping for every platform from a single codebase.
Kotlin Multiplatform project following a Layered Clean Architecture designed around a Unidirectional Dependency Flow.
- Android
- iOS
- Windows
- macOS
- Linux
- Web
| Source Set | Platform |
|---|---|
androidMain |
Android API 26+ |
appleMain |
iOS 16+ / macOS |
desktopMain |
JVM 21 |
webMain |
WASM-JS |
server |
JVM 21 |
- UI: Compose Multiplatform
- Client Database: SQLDelight
- Server Database Exposed
- Networking: Ktor
- Code Coverage: Kover
shared: Code that is reused across all target platforms (Client and Server).design: Design System where all UI components live.composeApp: Client side for Android, iOS, Desktop, and Web.server: The backend for the application.
The packages across these modules obey the same structure.
Each package has a specific isolated responsibility, and dependencies always point in a single direction down the stack.
- core: Business logic agnostic implementations. It is the foundation and cannot depend on any other layer.
- data: Responsible for data persistence and retrieval. Provides infrastructure for Network, Database and Storage. It can only depend on core.
- domain: Business workflows and rules. It can depend on data and core.
- ui: User-facing presentation layer. It can depend on domain, data and core.
- test: Test utilities like annotations and fake data shared across test source sets. It can depend on all layers, domain, data, core, ui.
- flow: Coroutine dispatchers.
Dispatcher: ProvidesMain,DefaultandIOcoroutine dispatchers as mutable properties so tests can substitute their own implementations.
- locale: Localization and date/time formatting.
DateTime: Utilities for getting the current time in UTC/ISO8601, epoch and duration calculation.
- platform: OS-specific APIs.
Platform: Provides a snapshot of the current execution environment with a sealed interface that defines the possible platforms that the application can run on.
- security: Cryptography and UUID utilities.
Uuid: UUID generation via the best available platform algorithm.
- telemetry: Logging and crash reporting.
Telemetry: Hub for dispatching telemetry data, including logs, error reports, and user feedback, by iterating over pluggableTelemetryEngineimplementations.
- http: Ktor configuration and network logic.
Header: Sealed class of all header keys.Query: Sealed class of all query parameter keys.URL: Sealed class of all remote endpoints, serving as a centralized registry for API routing.
- serializer: JSON parsing and serialization.
Json: Helpers for encoding/decoding.
Contains all the domain models.
Annotations used to exclude tests from coverage reports.
- translation: Translation related tools.
TranslationCache: A cache dedicated to translations.
Color: DefinesLocalColorSchemefor light and dark themes.Typography: DefinesLocalTypographyfor the text fonts.Shapes: DefinesLocalShapesfor the shape system.Translations: Composable helpers to read fromTranslationCache. ProvidesLocalTranslationState.Theme: Main app theme definition that uses the previously describedCompositionLocals.Preview: Wrapper composable that the application theme for accurate rendering in previews.- core: UI core components like
Text,Button,Image, etc. that provide the building blocks for composite components. - component: UI composite components for specific features built upon the core components.
- flag: Feature flags.
Flags: Data class with boolean controls for feature flags.FeatureFlags: Exposes flags for runtime toggling.
- player: Media Player implementations.
AudioPlayer: Abstraction with a sealedActioninterface (Play, Pause, Resume, Toggle). Manages playlist deduplication and shuffling and delegates platform-specific playback to subclasses.
- locale: Localization and date/time formatting.
Language: App default language and other language listings.Locale: Methods to get the current system language, locale-aware datetime formatting, and aFlowthat emits on locale changes.
- notification: Notification system implementation.
Notification: Platform specific implementation of a trigger of a native system notification defined byNotificationData.NotificationPayload: Exposes aFlowused to bridge the Native OS notifications interactions with the common code.
- platform: OS-specific APIs.
Development: Development mode flag.AppDataPath: Indicates the absolute path to the application's directory.
- security: Cryptography and UUID utilities.
Cryptography: Cryptography methods like encrypt/decrypt and hashing.
- telemetry: Logging and crash reporting.
PlatformLogger: ATelemetryEngineimplementation for native system console outputs.Console: An in-memory circular buffer for an in-app console feature.
- database: SQLDelight implementations, tables and drivers.
- adapter: List of adapters used to marshal and map data types to and from a database.
DatabaseFactory: Creates the mainAppDatabasewith the adapters.SqlDriver: Creates the database driver.NoOpSqlDriver: A no-op implementation ofSqlDriver.Database: Database extension helpers.
- http: Ktor configuration and network logic.
- plugin: Plugins used by the Ktor Http engine, like telemetry logging, timeouts, HTTP caching, encoding and JSON content negotiation.
HttpClientFactory: Creates ahttpClientwith the plugins.HttpClientEngine: Creates the http client engine.NoOpHttpClientEngine: A no-op implementation ofHttpClientEngine. Returns 204 for every request.Network: Network status helpers.Http: Extensions to execute type-safe requests and decode the response into aHttpResult<Success|Error>.
- resource: Resource index.
AudioResource: Sealed class functioning as a resource index for audio incommonMain/resources/tracks.ImageResource: Sealed class functioning as a resource index for images incommonMain/resources/drawable.JsonResource: Sealed class functioning as a resource index for JSONs incommonMain/composeResources/files.ResourceLoader: Loads resources via the Compose Resources API.
- storage: File system access.
File: Declarations for suspending save/load/delete file operations.Storage: ImplementsStorageFileinterface to manage the state and persistence of key-value files. Uses a Mutex-protected I/O to prevent race conditions and a read-only stream as an in-memory cache for faster fetch operations.StorageKey: Sealed class of keys used inStorageFileimplementations.
- device: Device specific code.
Device: Generates and fetches a device installation uuid.
- translation: Translation service.
TranslationService: Service to monitor locale and translations.
- notification: Notification service.
NotificationService: Notifications service that listens for user notifications.
- scheduler: Scheduler implementation.
Job: A persistent background execution unit handled by the scheduling subsystem.JobFactory: Translates Jobs into executable runtime actions and is implemented byJobProvider.Scheduler: Orchestrates dispatch logic by managing job queues destined for persistent execution and is implemented byJobScheduler.JobResult: Represents the final outcome of aJob.
- usecase: Implementation of specific business workflows. Each use case is a sub-package containing the interface and its gateway implementation.
Gateways: Aggregates all gateways under theUseCasesfile.
App: Main composable that assembles the application UI and acts as the top-level container for the user-facing elements.- lifecycle: Platform-aware lifecycle observers.
Lifecycle: Composable that registers foreground/background callbacks, with an optional recomposition key.
- player: Media Player composables.
AudioPlayer: Composable that manages audio playback respecting the app lifecycle.
- navigation: Routing logic.
- provider: Definitions of the navigation routes.
- scene: Scene strategies used to render a list of entries.
Screen: Sealed interface that enumerates all destinations.Router: Handles routing logic and manages the navigation backstack. It is implemented byNavigator.NoOpRouter: A no-op implementation ofRouter.Navigation: Composable that sets up the navigation and defines all the possible navigation destinations within the app.Routing: Navigation utility functions.
- component: UI components implementations. Each component is a sub-package containing the composable and respective store for state management, all co-located.
Store:ViewModelwith aStateFlow<State>as the single source of truth for the UI and reducer override to process actions from the UI.
- screen: These are the UI entry points built with components. Each screen is also sub-package containing the composable and respective store for state management, all co-located.
Screen: Wrapper composable that provides the foundational UI.
Dependency: Manual dependency injection. This class wires everything together. It initializes the full stack:SqlDriver→AppDatabase,HttpClientEngine→HttpClient, to be used by theSchedulerandUseCasesviaGateways.Application: Entry point of the application. It initializes theDependencygraph, telemetry, feature flags, user observer and services. Provides dependencyFlows that modules can observe to ensure initialization is complete before interacting with dependencies.
- platform: OS-specific APIs.
Env: Environment variables definitions.Property: Property definitions.
- security: Cryptography and UUID utilities.
Cryptography: Cryptography methods to hash and verify passwords.TicketManager: Manages single-use, short-lived tickets for connections.
- telemetry: Logging and crash reporting.
ServerLogger: ATelemetryEngineimplementation for server outputs.
- database: Exposed implementations, tables and drivers.
DatabaseFactory: Creates aR2dbcDatabase.Database: Database extension helpers.
- http: Ktor configuration and network logic.
- plugin: Plugins used by the Ktor Http engine.
- route: Defines the routing endpoints for the server.
- usecase: Implementation of specific business workflows. Each use case is a sub-package containing the interface and its gateway implementation.
Gateways: Aggregates all gateways under theUseCasesfile.
Fake data and demo accounts setup.
Application: Entry point of the server application. Initializes the telemetry logger and starts the server.
By default, signing keys and some envs are read from a local.properties file in the root directory.
Change this method at your leisure.
- Android Signing:
android.storeFile,android.keyAlias,android.keyPassword,android.storePassword. - Mac Notarization:
mac.sign.identity,mac.notarization.appleId,mac.notarization.teamId,mac.notarization.password. - Sentry Monitoring:
sentryDsnfor production monitoring. - Environment Variables:
server.port,server.jwt.issuer,server.jwt.audience,server.jwt.secret
New features should be gated behind a flag in Flags.kt. FeatureFlags exposes flags for runtime toggling.
Below are the steps to create a new isolated feature.
- Domain: Add the domain file(s) in the
domainpackage.
- UI Components: Add the needed components.
- Flag: Add in
Flags.ktthe feature:val {feature}: Booleanand set it to false onFeatureFlagsand true onApplication. - Components with Store: Create a new package
ui/component/{component}with files{Component},{Component}StateAction,{Component}Store. - Screen: Create a new package
ui/screen/{feature}with files{Feature}Screen,{Feature}StateAction,{Feature}Store. - UseCase: Create the use cases in
domain/usecaseand the needed.sqfiles in the foldersqldelight. - Scheduler: Create the needed jobs in
domain/scheduler/JobProviderfor offline capabilities. - Navigation: Add to the
ui/navigationpackage the new screen in the sealed classScreen, the new route in theproviderpackage and the link it in the composable navigation inNavigation, gated by the feature flag.
- Flag: Add in
Flags.ktthe feature:val {feature}: Booleanand set it to false onFeatureFlagsand true on Gradle Envs configuration. - Database: Add the feature entity to
data/databaseand the table creation inDatabaseFactory. - UseCase: Create the use cases in
domain/usecase. - Route: Add the feature routes in
domain/routein theproviderpackage and the link it in theRoutingfile, gated by the feature flag.
Compose screens use a custom MVI Store pattern. Each screen has a Store ({Screen}Store) and a Screen composable ({Screen}Screen). Jobs inside a Store can be launched with an ID to cancel/replace prior work.
The UI state uses kotlinx.collections.immutable (ImmutableList, ImmutableSet) to prevent accidental mutations.
Store<State, Action> (extends ViewModel) is the base class:
stateFlow: StateFlow<State>— single source of truth observed by the composablesend(action)→reducer(state, action)— the only entry point for UI eventsupdateState { }— the only way to mutate statelaunch(id, replace, context) { }— launches a coroutine tied to an IDFlow<T>.observe(id) { }— lifecycle-aware collection that pauses after the UI unbinds and resumes when it reattaches
On Android, use the applicationContext provided via KInitializer to avoid explicit context injection.
The testing structure mirrors the source code to ensure 1:1 coverage.
Coverage excludes @Serializable classes, @Preview composables, and anything annotated with @ExcludeFromTesting.
Write tests in commonTest whenever possible. Platform-specific test setup lives in the PlatformTestCase expect/actual classes.
- Unit/UI Tests: Should run in the
commonTestsource set whenever possible. Use theTestCaseharness for hermetic Unit/UI testing with mock engines. - Coverage: Kover is configured to verify a minimum of 90% code coverage.
- Command: Run all tests using
./gradlew clean testAllAndReport.
All client tests extend TestCase, which provides a hermetic environment:
dependency—Dependencywith an in-memory SQLDelight driver and a mock Ktor enginerunUnitTest { }— Sets up the test environment, resets all data, runs unit test then tears downrunUITest { }— Same thing but for UI test. UsesetUI { }to render composables underAppThemewith mock lifecycle and navigation
WIP
WIP
Bump versions in the files:
- build.gradle.kts
- info.plist
- project.pbxproj
Standard compile commands for different platforms include:
- iOS: Xcode archive
- Android:
./gradlew clean bundleRelease - Mac:
./gradlew clean notarizeDmg --no-configuration-cache - Windows:
./gradlew clean packageMsi - Linux:
./gradlew clean packageDeb - Web:
./gradlew clean deployWeb - Server:
../gradlew :server:buildFatJar