distage is a pragmatic module system for Scala and Scala.js. It combines the simplicity and expressiveness of pure FP with the flexibility and extreme late-binding, traditionally associated with Java dependency injection frameworks, such as Guice.

distage supports any Scala style, whether it’s Tagless Final Style, ZIO Layer, ordinary FP, actor-based or imperative Scala.

Getting started

The best way get started is to clone distage-example sample project and play around with it.

It shows how to write an idiomatic distage application from scratch and how to:

Why distage?

  1. Faster applications and tests: distage guarantees that no unnecessary instantiations will happen during your tests or application startup. distage itself is very fast, in part due to not using Java reflection.

  2. Faster integration tests: distage-testkit allows you to reuse expensive resources (such as database connections and docker containers) across multiple test suites, gaining performance without sacrificing correctness.

  3. Managed test environments: distage-testkit eliminates all the hard work of setting up test environments, especially configurable ones. Easily describe tests environments, share heavy resources across all the test suites in the environment, use the power of DI to override components and run your tests under different scenarios.

  4. Compile-time error detection: distage can detect wiring errors at compile-time for fast feedback during development. Despite that, distage extensions are simple to write and do not require type-level programming.

  5. Early failure detection: distage performs all the integration checks for your application and tests even before any instantiations happen.

  6. Simplify development workflow: distage-framework allows you to develop Role-based applications, letting you run all your services in one process for development purposes (and even switch to mock implementations with a single commandline argument).

  7. Easy deployment: Role-based applications allow you to deploy and orchestrate fewer containers and achieve a higher computation density.

  8. Simple debugging: distage provides you insights about your application structure and allows you to introspect and modify it on the fly, before any instantiations happen.

  9. Lifecycle management: distage supports resources and lifecycle natively and guarantees proper cleanups even when something went wrong.

  10. Non-invasive: distage is designed to not impact the way your Scala code is written, it just removes all the initialization boilerplate. You don’t need to learn magic tricks to write components in a distage application.

  11. Cross-platform: distage is available for JVM, Graal Native Image and Scala.js.

Given its native support for type classes and higher-kinded types – both features indispensable to functional programming – distage is one of the leading dependency injection libraries out there. Bonus points for being built by a wicked-smart team that contributes to ZIO!

John A. De Goes


Q: How to pronounce distage?

A: ‘Dee-stage’

Q: How do I switch between production and test implementations of components?

A: Use Activation Axis


Further reading

Example projects:

Support Chats: