Elixir Examples
Advanced 30 min read Phase 7

Umbrella Apps and Monorepo Architecture

Structure large Elixir systems with umbrella apps and monorepo boundaries. Covers app decomposition, dependencies, shared code, and team-scale workflows.

Umbrella projects are useful when a system grows beyond a single application but still benefits from coordinated development in one repository.

When Umbrella Makes Sense

Use umbrellas when:

  • multiple deployable components share domain code,
  • teams need clear ownership boundaries,
  • coordinated refactors are frequent.

Avoid umbrellas when:

  • services are fully independent and versioned separately,
  • deployment cadence differs heavily between components.

Typical Layout

apps/
  core_domain/
  billing/
  web/
  worker/

Each app has its own mix.exs, dependencies, and OTP application config.

Dependency Rules

Strong pattern:

  • domain apps depend only on stable lower-level libraries,
  • web/worker apps depend on domain apps,
  • never create circular dependencies.

Document these rules early and enforce in code review.

Shared Code Strategy

If code is reused by 2+ apps, extract it into a dedicated internal app with explicit API boundaries. Avoid ad-hoc imports from random sibling apps.

Build and CI Considerations

  • run tests per app and for integration paths,
  • cache dependencies at umbrella level,
  • support targeted CI for changed apps where possible.
# Monorepo with multiple packages/services
# Similar trade-offs: shared tooling vs independent release cadence.
// Monorepo with workspaces/turborepo
// Shared packages + service apps in one repository.
# Umbrella
# Native Mix support for multi-app codebases with shared tooling.

Exercise

Split a Single App into an Umbrella

Take an existing app and split it into two apps:

  1. Extract core business logic into core_domain.
  2. Keep web adapters in web.
  3. Move shared contracts/types into explicit modules.
  4. Add tests that validate cross-app integration.
  5. Document dependency direction rules in the repo.

FAQ and Troubleshooting

Why does app startup fail after splitting?

Check application dependencies and startup order (extra_applications, supervision trees, and runtime config).

How small should each app be?

Split by ownership and change boundaries, not by arbitrary size.

Should every large Elixir repo become umbrella?

No. Umbrellas solve specific coordination and boundary problems; they add structure and overhead.

Related Lessons

Further Reading on HexDocs

Mix Umbrellas Application

Key Takeaways

  • Umbrella apps help enforce boundaries in growing Elixir systems
  • Dependency direction and ownership rules matter more than folder layout
  • Shared code should be explicit libraries, not accidental cross-app coupling