โš™๏ธ Advanced Android Engineering and Emerging Technology

Android App Architecture at Scale

Architecture that works for 10 screens and 3 developers breaks at 300 screens and 50 developers, not because patterns are wrong, but because new problems appear: build times, ownership, cross-feature consistency, experiments and governance. Here's how large Android apps evolve their architecture.

โœ๏ธ Yunok Tech ๐Ÿ“… Updated โฑ 3 min read ๐ŸŽฏ Advanced
On this page
  1. The shape of a large Android app
  2. 1. Strong boundaries
  3. 2. Shared state, done deliberately
  4. 3. Navigation across features
  5. 4. Performance budgets
  6. 5. Experimentation and flags
  7. 6. Consistency and governance
  8. 7. Data consistency at scale
  9. Evolution stages
  10. Frequently asked questions
  11. Conclusion

At scale, the hardest architecture problems are organisational and systemic: how 10 teams ship independently without breaking each other, how features share user state consistently, how the app stays fast as everyone adds code, and how decisions stay coherent across years.

The shape of a large Android app

Layered architecture of a large Android app At the top, the app shell handles navigation, DI assembly and startup. Feature modules owned by teams sit below, each with UI, ViewModels and feature data. Shared domain and data services provide cross-feature state such as session, user and cart. A platform layer provides networking, storage, design system, analytics, feature flags and performance tooling. App shell: navigation host, DI assembly, startup orchestration Feature: Catalog Feature: Cart Feature: Payments Feature: Account Shared domain services: session, user, cart state, entitlements Platform: network ยท storage ยท design system ยท analytics ยท flags ยท perfowned by a platform team
Features depend downward only. Cross-feature state lives in shared services, not in other features.

1. Strong boundaries

  • Feature modules with public API modules for cross-feature contracts. See Modularization Strategies.
  • Enforced dependency rules in CI, not just conventions.
  • Teams own modules (CODEOWNERS), with clear on-call and quality responsibility.

2. Shared state, done deliberately

User session, cart contents and entitlements are needed by many features. Put them in shared services with observable APIs, and a single source of truth for each:

Shared session service contractKotlin
interface SessionService {
    val session: StateFlow<Session>               // SignedOut | SignedIn(user, entitlements)
    suspend fun signOut()
}

sealed interface Session {
    data object SignedOut : Session
    data class SignedIn(val userId: String, val entitlements: Set<String>) : Session
}
// Features observe; only the auth feature mutates via its own API.

Features expose route keys or entry points through API modules. The app shell assembles the navigation graph, so features never reference each other's screens directly. Deep links resolve to keys centrally. See Navigation in Compose.

4. Performance budgets

  • Set budgets: cold start, frame metrics on key screens, APK size, memory.
  • Run Macrobenchmarks in CI, and alert on regressions per PR or nightly.
  • Control startup centrally: features register initialisers with priorities, so nobody adds work to Application.onCreate unreviewed.

5. Experimentation and flags

Large apps run many experiments at once. Centralise flag evaluation and exposure logging, keep flag reads out of deep business logic (inject decisions), and clean up flags after launch. See Scaling Across Teams.

6. Consistency and governance

  • A design system module with screenshot tests.
  • Architecture decision records and lightweight design reviews for cross-cutting changes.
  • Templates and convention plugins for new features.
  • Lint rules encoding team conventions.

7. Data consistency at scale

Multiple features caching the same entities leads to inconsistency. Prefer shared repositories over a common database for core entities, and event-driven invalidation (for example push-triggered refresh) for data that changes server-side.

Evolution stages

StageTypical architecture work
Growing (5โ€“15 devs)Feature modules, design system, Hilt, CI tests, flags
Large (15โ€“50 devs)Platform team, API modules, performance CI, startup orchestration
Very large (50+)Governance, ADRs, dependency rules, build optimisation, internal tooling

Frequently asked questions

Does scale require Clean Architecture everywhere?

No. Consistent boundaries matter more than uniform layering. Some features need a domain layer and others don't.

Should large apps use multiple Activities?

Single-Activity with Compose navigation is common, but some entry points (share targets, widgets) need their own Activities. Choose per use case.

Conclusion

Architecture at scale means enforced boundaries, deliberate shared state, centrally assembled navigation, performance budgets in CI, managed experimentation and lightweight governance, so many teams can ship independently while the app stays coherent and fast.

Next step: keep builds fast as the codebase grows with Multi-Module Gradle Builds and Build Optimization.

Official references

๐Ÿ“ฑ Apps built by Yunok Tech

Real Android apps on Google Play, free to download.

See all our apps โ†’

Ready to build real Android applications?

Architecture makes the most sense when you apply it to a real project and see why each boundary exists. Learn how maintainable Android applications are designed by building one.

Move beyond theory and strengthen your Android development skills with Yunoktech's Android course. Learn core concepts, practical implementation, modern Android development techniques, and the reasoning behind building maintainable applications.

Explore the Android course and take your next step as an Android developer.

Share: LinkedIn X / Twitter WhatsApp