# Shopping-By-KMP: one Kotlin codebase for Android, iOS, web, desktop and TV

> Shopping-By-KMP is a full-stack Compose Multiplatform sample with a Ktor backend and a MySQL database, where the same declarative UI runs on six targets. Its value is as a working reference for the awkward parts of Kotlin Multiplatform, from a shared module layout to a convention plugin for the Gradle build.

**razaghimahdi/Shopping-By-KMP** — This is a cross-platform application that is built using Jetpack Compose Multiplatform, a declarative framework for sharing UIs across multiple platforms with Kotlin.

- Repository: https://github.com/razaghimahdi/Shopping-By-KMP
- Website: https://github.com/razaghimahdi/Shopping-By-KMP
- Stars: 559 · Forks: 98
- Language: Kotlin
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/razaghimahdi-shopping-by-kmp

## What the project is, and the platform list that makes it interesting

Shopping-By-KMP is a cross-platform, full-stack application built entirely in Kotlin, using Jetpack Compose Multiplatform to share declarative user interfaces across multiple platforms, with a Ktor backend engine powering the data layer.

The platform list is the headline. The application lets users browse, search and purchase products from a shopping catalogue on Android, iOS, Desktop, Web, Automotive and AndroidTV. The README carries separate sections with runnable demonstrations for Android and iOS, for Desktop, for Android TV, and for the web, and the web build is deployed live on GitHub Pages.

The reason that list matters is that each of those targets pulls in a different rendering and input model. A phone, a desktop window, a browser tab, a car head unit and a television are not the same application, and a shared Compose codebase has to absorb the differences. When the project says the UIs are declarative and shared, that is the interesting claim, because the difficult part of Kotlin Multiplatform is not the code that compiles, it is the platform-specific seams.

The features table lists twelve implemented areas: login and sign up, home, product detail and comments, wishlist, cart and basket, profile and edit profile, search and category, manage address, payment method, my orders, my coupons, and notifications and settings. That is a complete shopping application, not a widget demo, and the breadth is what makes it worth reading as a reference.

The licence is MIT, the primary language is Kotlin, the last push was on 2026-09-20, and the topic list names the architecture as well as the platforms: clean-architecture, mvi, ktor, compose, kmm, swift and android.

## The feature set, and what the project added most recently

The latest features section lists what changed in the recent work, and it is the part that shows where the project was pushed.

Full-stack KMP architecture is the headline. The project has officially migrated to a full-stack monorepo, with a nested server Ktor module that connects to a local MySQL database, eliminating the need for fake data and allowing end-to-end Kotlin development.

That is the single most consequential change for anyone reading the code, because a KMP sample that used fake data had a data layer defined by the client module, and moving the server into the same repository changes what shared means. The core module now holds the contract, and the server implements it.

Then the platform additions, each with its own application module. Automotive support added an AutomotiveApp for Android Automotive OS. Web support introduced a WebApp for the browser. Android TV support added a TvApp. Desktop support introduced a DesktopApp for Windows, macOS and Linux.

And one feature that is not a platform but changes the user experience: Google Maps integration for address input, with a GoogleMap component so a user can pick their location on the map before filling in address details.

Two things are worth noticing about how the project is presented. First, the earlier related articles are all by the same author and cover the parts that are hard to derive from the code: handling errors in Compose with MVI and clean architecture, setting up a convention Gradle plugin for Compose Multiplatform, custom number formatting in Compose Multiplatform, and file upload in Compose Multiplatform using Ktor.

Second, and more telling for an evaluator, the project asks for a star with the explanation that you should give one if you are using the project to learn or to start your solution. That tells you the author's intent: this is a teaching artefact, and the star is the feedback loop.

## The module layout, and the stack on each side

The architecture section describes a Clean Architecture and MVI implementation in a modular, full-stack Gradle setup, with three top-level modules.

The core module holds the shared DTOs, models and networking constants used by both client and server. That is the contract, and it is the module that has to stay free of platform dependencies, which is the constraint that makes the rest of the design work.

The server module is the Ktor JVM backend engine and its database configuration. The app module is a nested directory containing the platform specific targets, named androidApp, desktopApp and webApp, and the shared Compose user interface module, named shared.

The client side stack is Kotlin Multiplatform with coroutines, Compose Multiplatform for the interface, Material3 for the design system, the Ktor client for networking, Datastore for local storage, Compose Navigation for type safe navigation, Koin for dependency injection, and Coil3 for image loading with global interceptors.

The server side stack is Ktor Server on Netty, Exposed as the SQL ORM, MySQL with HikariCP for the database and connection pooling, BCrypt for password hashing, and JWT authentication.

Two entries deserve a note. Coil3 with global interceptors is the image loading layer, and the interceptor part is the interesting bit, because it is how a shared client gets authentication headers attached to every image request without each call site handling them. And BCrypt with JWT on the server is a conventional choice, with BCrypt doing the password hashing at rest and JWT carrying the identity afterwards.

The repository root supports the multiplatform picture. There is a build-logic/ directory, which is where a convention plugin for the Gradle build lives, alongside a root build.gradle.kts and settings.gradle.kts, the app, core and server directories, and a cleanup.sh script. The build-logic directory is what makes the repeated configuration across six targets manageable, and the author has written an article about setting up exactly that.

## Running the backend, and the two steps that will trip you up

The quick start section covers the server, and the reason it exists separately is that the project now runs on an integrated Ktor 3.x backend connected to a local MySQL database.

There are three steps, and the first two are the ones that need a moment of attention.

Ensure MySQL is running on your machine on port 3306, and create a new database named shopping_db. Then open DatabaseFactory.kt inside the server module and update the user and password variables to match your local MySQL configuration.

That second step is worth pausing on. The credentials are in source code rather than in a configuration file or an environment variable, which is a common simplification in a sample and a bad pattern to carry into a real project. It is fine for a repository that exists to be read, and it is exactly the kind of thing you would replace with something environment driven when you build on it.

The third step is the run command, which is a Gradle task that auto-generates the database tables and starts the API:

```bash
   ./gradlew :server:run
```

The API comes up on http://localhost:8080, or on 10.0.2.2 for Android emulators, since that address is how the emulator reaches the host machine rather than the host's own loopback interface. It is a small detail that is the first thing that goes wrong for anyone running the Android client against a local backend, and having it written down saves an afternoon.

The auto-generated tables are the other thing to know. The schema is created by the server on startup rather than by a migration tool, which means there is no migration history to inspect or to roll forward. For a sample that is a reasonable trade, since the schema can be recreated from scratch at any time, but it is not a pattern to copy into a system whose data matters.

## What this sample is for, and where it stops

It is worth being explicit about the value, because a KMP sample is not a product and reading it as one leads to the wrong conclusions.

The value is in the parts that are hard to derive. The module split with a shared core holding the contract, the Ktor server living in the same repository so the DTOs and the endpoints cannot drift, and the Gradle build-logic directory that keeps six platform targets from turning into six copies of configuration. Those are the seams that take a team weeks to get right, and here they are in one place with the working code around them.

The MVI and clean architecture framing is the other part. With MVI, the user intent is a distinct input to the state machine, and the state is a single observable value that the interface renders. In a shared Compose codebase, that discipline is what stops each platform from inventing its own way of handling a result, and the author's separate article on error handling in Compose with MVI and clean architecture suggests it is the part of the project he has thought about most.

Where it stops is less interesting. It is a shopping application, so the domain model, the schema and the twelve feature areas are all specific to that domain and none of it transfers to another product. The DataStore usage, the Koin modules and the navigation graph are the transferable parts, and even those are presented as one arrangement rather than as a set of options.

The release history is worth a mention too, and it is unusual. The recent releases are numbered 74, 73 and 72, all on 2026-09-20, with titles of the form Shopping-By-KMP followed by the version. So this is a project that tags a build per push, more like continuous delivery than a release line. There is no semantic version to pin and no migration path between tags, which tells you the tags are markers of progress rather than published artefacts.

## Conclusion

Use Shopping-By-KMP as a reference implementation if you are building a Compose Multiplatform application and want to see how the module layout, the shared data layer and the Ktor backend fit together in one repository. Do not adopt it as a starting application, because it is a sample with a shop domain, a MySQL schema and a set of hard-coded feature decisions. Before you run the backend, create the shopping_db database, edit the user and password variables in DatabaseFactory.kt to match your local MySQL, and run the server Gradle task, and note that the release tags are numbered builds rather than semantic versions, so there is no migration path to follow.

## FAQ

### Which platforms does the Shopping-By-KMP application support?

Android, iOS, Desktop on Windows, macOS and Linux, Web, Automotive for Android Automotive OS, and Android TV. Each has its own application module in the app directory, alongside a shared Compose UI module.

### What backend does Shopping-By-KMP use?

A Ktor 3.x backend in a nested server module, connected to a local MySQL database, using Exposed as the SQL ORM with HikariCP for connection pooling, BCrypt for password hashing and JWT authentication.

### How do I run the Shopping-By-KMP backend locally?

Ensure MySQL is running on port 3306 and create a database named shopping_db, then open DatabaseFactory.kt in the server module and set the user and password variables, and run ./gradlew :server:run, which creates the tables and starts the API on http://localhost:8080, or 10.0.2.2 for Android emulators.

### What architecture does the Shopping-By-KMP project use?

Clean Architecture with the MVI pattern in a modular full-stack Gradle setup: a core module with shared DTOs, models and networking constants, a server module with the Ktor backend and database configuration, and an app module holding the platform targets and the shared Compose UI module.

### What client libraries does the Shopping-By-KMP project use?

Kotlin Multiplatform with coroutines, Compose Multiplatform, Material3, the Ktor client for networking, Datastore for local storage, Compose Navigation, Koin for dependency injection, and Coil3 for image loading with global interceptors.

## Sources

- [License: MIT](https://github.com/razaghimahdi/Shopping-By-KMP/blob/master/LICENSE)
- [Project website](https://github.com/razaghimahdi/Shopping-By-KMP)
- [razaghimahdi/Shopping-By-KMP on GitHub](https://github.com/razaghimahdi/Shopping-By-KMP)
- [README](https://github.com/razaghimahdi/Shopping-By-KMP/blob/master/README.md)
- [Releases](https://github.com/razaghimahdi/Shopping-By-KMP/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/razaghimahdi-shopping-by-kmp
