Skip to content
All posts
April 28, 20264 min read

How I Built 22 Android Apps Solo — Systems, Not Hustle

From zero to 22 live Play Store apps as a solo developer. The architecture decisions, tooling, and mental models that made it possible without burning out.

AndroidSolo DevKotlinPlay StoreArchitecture
Share:

22 apps on Google Play. Solo. No team. No funding. No co-founder.

People ask how. The honest answer: systems, not hustle. I didn't work 18-hour days. I built infrastructure that compounds — so every new app is easier than the last.

Here's exactly how it works.


The Foundation: One Architecture, Every App

The biggest time-killer for any developer is decision fatigue. What folder structure? What DI framework? What state management approach?

I made those decisions once, then never made them again.

Every app I ship uses the same foundation:

code
app/
├── data/
│   ├── local/          # Room, DataStore
│   ├── remote/         # Retrofit, Firebase
│   └── repository/     # Repository implementations
├── domain/
│   ├── model/          # Pure Kotlin data classes
│   ├── repository/     # Repository interfaces
│   └── usecase/        # Business logic, one action each
└── presentation/
    ├── ui/
    │   └── screen/     # Composables per screen
    └── viewmodel/      # StateFlow-based ViewModels

MVVM + Clean Architecture + Hilt + Jetpack Compose. Same package structure. Same naming conventions. Same patterns for state, navigation, data flow.

When I start app #23, I'm not starting from zero. I'm copying a scaffold and filling in product logic.


The ViewModel Pattern I Use Everywhere

Every ViewModel follows this exact shape:

kotlin
@HiltViewModel
class HomeViewModel @Inject constructor(
    private val getAppsUseCase: GetAppsUseCase
) : ViewModel() {

    private val _uiState = MutableStateFlow<HomeUiState>(HomeUiState.Loading)
    val uiState: StateFlow<HomeUiState> = _uiState.asStateFlow()

    init {
        loadApps()
    }

    private fun loadApps() {
        viewModelScope.launch {
            getAppsUseCase()
                .onSuccess { apps ->
                    _uiState.value = HomeUiState.Success(apps)
                }
                .onFailure { error ->
                    _uiState.value = HomeUiState.Error(error.message ?: "Unknown error")
                }
        }
    }
}

sealed interface HomeUiState {
    data object Loading : HomeUiState
    data class Success(val apps: List<App>) : HomeUiState
    data class Error(val message: String) : HomeUiState
}

No LiveData. No nullable state. No guessing what state the UI is in.

code
StateFlow
+ sealed interfaces give you exhaustive when expressions in Compose.


Tooling That Multiplies Output

Claude Code as Pair Programmer

Every new screen, every new feature — I describe the pattern once. My custom skills encode my exact architecture conventions, so the generated code is immediately mergeable.

I built skills for:

  • Scaffolding a new screen (ViewModel + Composable + UseCase + Repository method)
  • Adding a new Room entity with DAO
  • Setting up a new Hilt module

The output isn't boilerplate I have to fix. It's production-ready code that matches my conventions exactly.

Version Management at Scale

22 repos. Same version tracking system:

properties
# config/version.properties
VERSION_MAJOR=1
VERSION_MINOR=3
VERSION_PATCH=2
VERSION_CODE=47

One script bumps them all:

bash
./version-bump.sh patch MyFamilyTracker
# → VERSION_PATCH=3, VERSION_CODE=48

No manual version editing. No off-by-one mistakes. No forgetting to bump before release.

Signing Automation

Every app is signed the same way. Keystore credentials live in

code
local.properties
(never committed). The
code
build.gradle.kts
reads them:

kotlin
signingConfigs {
    create("play store") {
        val props = Properties().apply {
            load(rootProject.file("local.properties").inputStream())
        }
        storeFile = file(props["KEYSTORE_PATH"] as String)
        storePassword = props["KEYSTORE_PASSWORD"] as String
        keyAlias = props["KEY_ALIAS"] as String
        keyPassword = props["KEY_PASSWORD"] as String
    }
}

No hardcoded credentials. No "which keystore did I use for this app?" panic.


The QA Background Is a Superpower

13+ years in QA before I started building. People assume this was a liability — "you're not a real developer." It's the opposite.

QA engineers see what breaks. Developers who came up through QA ship things that don't.

What QA thinking gives you as a solo dev:

  • You write error handling because you've seen what happens when you don't
  • You test edge cases because you know users find them
  • You structure releases carefully because you've watched bad releases wreck products
  • You document because you've debugged undocumented code at 2am

My apps don't have 5-star ratings because I'm a genius. They have good ratings because I think like a tester when I build.


What "Solo" Actually Means

Solo doesn't mean isolated. It means:

Solo advantageWhat it enables
No approval chainsShip when it's ready, not when the process allows
No coordination overheadMove at the speed of the idea
Full ownershipEvery decision is yours — and so is every lesson
No meetingsThat's just 8 hours back per week

The 22 apps aren't 22 side projects. They're 22 bets. Some will grow. Some won't. The ones that do get depth — real features, real maintenance, real user relationships.


What's Next

The goal isn't 50 apps. It's depth.

Pick the apps with real traction. Build them into something people rely on every day. Stop treating every app like a portfolio piece and start treating the best ones like products.

If you're thinking about building solo:

  1. Pick your stack and commit to it. Decision fatigue is your enemy.
  2. Build your first app all the way to production. Not to "done," to shipped.
  3. Automate everything you do twice. The third time it should run itself.

Everything else is learnable on the way.

Share:
S

Sudarshan Chaudhari

AI Systems Builder / Product Engineer

Bangkok, Thailand

Solo Android developer with 13+ years in QA, building Android apps, AI automation systems, and developer tools at SudarshanTechLabs.

Stay updated

Get new posts on Android, Kotlin, and solo dev straight to your inbox.

Newsletter preferences

Related Apps

MyFamilyTracker

Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.

Building something? Available for Android dev and QA consulting.

Work with me

Comments — powered by Giscus

Apps tagged with this