Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Dagger builds a dependency graph at compile time and generates code to create and connect the objects your application requests. For a new Android app, Android Developers recommends Hilt, which is built on Dagger and handles much of Android-specific setup. This tutorial focuses on raw Dagger for learning the underlying graph, using it outside Android, or maintaining an existing Dagger project.

What Dagger does

Dependency injection means an object receives the collaborators it needs instead of constructing them throughout the codebase. Dagger analyzes those relationships during compilation, then generates code to provide requested objects and their dependencies. The project describes Dagger as a static, compile-time framework that does not rely on reflection or runtime bytecode generation: Dagger.

That compile-time approach means missing or ambiguous bindings are reported while building, rather than being discovered only when a runtime container tries to resolve an object. Dagger is not an object factory that guesses how to create every type: you describe the graph through injectable constructors, bindings, provider methods, and a component.

Set up Dagger in your project

Dagger needs its runtime library and a compiler integration that generates the implementation code. The exact configuration depends on the build system and language; use the current setup instructions for your project rather than copying a version placeholder from an example.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Java: The Android Developers Dagger guide demonstrates the Dagger runtime artifact and dagger-compiler configured with annotationProcessor.
  • Kotlin: Its Kotlin example applies kotlin-kapt and configures the compiler with kapt. Use the processing setup compatible with your Kotlin and build configuration.

At the time Android Developers’ guide was consulted for this tutorial, the Dagger site listed version 2.60.1 on 2026-09-30. That is a dated release identifier, not a guarantee it remains the latest; check the Dagger project site or Google Dagger repository when choosing a version.

Build a graph with constructor injection

1. Mark constructible classes

When Dagger can create a class by calling its constructor and supplying that constructor’s dependencies, annotate the constructor with @Inject. This is the simplest binding and usually the best starting point.

import javax.inject.Inject

class Engine @Inject constructor()

class Car @Inject constructor(
    private val engine: Engine
)

In this example, requesting a Car requires an Engine. Dagger can construct the engine first, then pass it into the car’s constructor. In Java, the corresponding declaration uses @Inject on the constructor:

final class Engine {
    @Inject
    Engine() {}
}

final class Car {
    private final Engine engine;

    @Inject
    Car(Engine engine) {
        this.engine = engine;
    }
}

The imports and processing configuration must match the project’s language and dependencies. In particular, use the injection annotations provided by the Dagger setup rather than assuming every project has identical imports.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

2. Bind interfaces to implementations with @Binds

Dagger cannot infer which implementation to use when code requests an interface. Define that relationship in an abstract module with an abstract @Binds method:

interface Engine

class ElectricEngine @Inject constructor() : Engine

@Module
abstract class EngineModule {
    @Binds
    abstract fun bindEngine(implementation: ElectricEngine): Engine
}

The binding says that a request for Engine can be satisfied by ElectricEngine. The implementation still needs a way to be constructed, such as an injectable constructor or another binding.

3. Describe explicit construction with @Provides

Some dependencies cannot use constructor injection—for example, a type from a library that your project does not own, or an object that must be built by calling a factory. Supply a @Provides method in a module:

class ApiClient private constructor(val baseUrl: String) {
    companion object {
        fun create(baseUrl: String) = ApiClient(baseUrl)
    }
}

@Module
object NetworkModule {
    @Provides
    fun provideApiClient(): ApiClient = ApiClient.create("https://api.example.com")
}

Here the module tells Dagger exactly how to obtain an ApiClient. Use @Provides when construction needs executable code; prefer constructor injection for types whose creation Dagger can handle directly.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Assemble and request dependencies with a component

A component defines the graph boundary. It identifies modules that contribute bindings and exposes dependencies that callers can request. Dagger generates the component implementation during compilation.

@Component(modules = [EngineModule::class])
interface CarComponent {
    fun car(): Car
}

With the constructor-injected Car and ElectricEngine, and the interface binding from EngineModule, the component can provide a Car. Conceptually, Dagger follows this chain:

  1. A caller requests Car from the component.
  2. Dagger sees that the Car constructor needs Engine.
  3. The module maps Engine to ElectricEngine.
  4. Dagger constructs ElectricEngine and passes it into the Car constructor.

For a plain JVM example, a component can be created and used through its generated factory:

val car = DaggerCarComponent.create().car()

Generated class names and available factory methods follow the component and module configuration. If the build cannot find the generated implementation, check that annotation processing is enabled and that every requested type has a valid binding.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Use scopes to express object lifetime

A scope marks bindings whose instances should be reused within the lifetime of a component instance. It does not create a component, choose an application architecture, or make every object global. The component determines the graph boundary; the scope communicates the intended reuse within that boundary.

Apply a scope only when the object should have that lifetime. For example, a long-lived service may belong in a component that also lives for a long time, while short-lived values need not share that scope. Avoid putting every binding in a single application-wide scope simply because it is available.

For Android apps, consider Hilt before raw Dagger

Android Developers’ guidance is direct: “Use Hilt for dependency injection on Android.” Hilt is built on Dagger and provides standardized Android components, scopes, Android bindings, and qualifiers, reducing the integration work that a raw Dagger setup would otherwise require. Read the official Hilt documentation when starting Android dependency injection.

Choice What it offers Good fit
Raw Dagger Direct control over the dependency graph, with Android-specific wiring handled by the project. Learning Dagger’s underlying graph, non-Android Java or Kotlin projects, or maintaining an existing Dagger graph.
Hilt Dagger-based Android integration with standardized components, scopes, bindings, and qualifiers. Most new Android apps that need dependency injection, following Android Developers’ recommendation.

Android Developers says Dagger and Hilt can coexist, while generally recommending Hilt to manage Dagger use across an Android app. For setup and migration context, see Using Dagger in Android apps.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How to treat older dagger.android tutorials

The Dagger documentation marks dagger.android as being in maintenance mode and points Android developers toward Hilt: Dagger’s dagger.android guide. A 2021 tutorial may help explain or identify patterns such as HasAndroidInjector and AndroidInjection.inject in an existing codebase, but it should not be taken as the recommended starting setup for a new Android application. One example is Simplified Coding’s 2021 Dagger 2 Android tutorial.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.