1.2.0
New
- [interop] This release introduces experimental support for Hilt
@InstallInand@EntryPointinterop.- Enabled with
metro { interop { includeHilt() } } - A
@DependencyGraph(<scope>)automatically merges every@InstallIn(<component>) @Module(as a binding container) and@InstallIn(<component>) @EntryPoint(as a supertype) whose<component>maps to<scope>.- The eight standard Android Hilt components map to their canonical scopes out of the box.
- User-declared
@DefineComponentinterfaces are resolved on demand by looking for an annotation on the same interface whose annotation class is itself annotated with@Scope(Hilt's own convention).
- Both consuming Hilt-generated aggregation deps and also treating
@InstallIn+@EntryPoint/@Moduleas interop are supported. - See the docs for the details and current limitations.
- Enabled with
Enhancements
- [compat] Improve IDE kotlinc version resolution. IntelliJ uses custom tags like
2.4.0-ij261-64that are a little tricky to decipher. - [FIR] Add diagnostic guidance around
inline@Providesdeclarations. TL;DR, they only make sense for public providers. - [FIR/IR] Inline constant
@Providesbindings directly into generated graph implementations when possible, avoiding generated factory calls for literals, nulls, object singletons, enum entries, class literals, andconstproperty reads. This is enabled by default and can be disabled with theenable-provider-inliningcompiler flag if you see any issues. - [IR] Add a
member-naming-strategycompiler option for shortening generated member names in generated code. AcceptsDESCRIPTIVE(default),TYPED(provider*/instance*/factory*), orMINIMAL(single collapsedprovider*naming). See docs/performance.md for guidance. - [IR] Lazily compute cached hashCode and toString renders for compiler-internal type keys without delegation.
- [IR] Propagate
inlinemodifiers from@Providesfunctions to factorynewInstance()functions. - [IR] Preserve concrete generated provider factory return types where possible instead of widening to
Factory<T>. In the future, Metro may generate these as value classes and this will allow better compiler optimization in those scenarios. - [IR/IC] Optimize IC tracking by buffering lookup and expect/actual records during IR and flushing them once after graph validation, avoiding per-write synchronization on the hot path. This is enabled by default but can be disabled via the
buffered-ic-trackingcompiler option if it causes any issues. - [IR/IC] Use newer compiler
DeclarationFinderAPIs on Kotlin2.3.20+. These have more granular search scopes plus automatic IC tracking. - [IR/runtime] Add internal primitive instance factories and use them where possible for primitive graph inputs and inlined providers.
- [gradle] Add a
metroEnvtask that writes human-readable Metro/Kotlin/Gradle environment reports for bug reports. - [reporting] Add compiler stats to reporting.
- [runtime] Rework
DoubleChecksynchronization on JVM and native targets.- On JVM, scoped bindings now synchronize on the
DoubleCheckinstance's own monitor (like Dagger) instead of allocating aReentrantLockper instance, which also eliminates the spuriousReservedStackAccessJVM warning. - On native targets, the previous spinlock impl is replaced with a reentrant init guard whose contended callers park on a process-wide condition variable instead of busy-waiting.
- On Apple platforms, parked waiters additionally donate their QoS class to the initializing thread to avoid priority inversion.
- Notes for virtual thread (i.e. Project Loom):
- On JVM, scoped bindings now synchronize on the
Fixes
- [FIR] Loosen
nonPublicContributionSeverityifgenerateContributionProvidersis enabled. Note it will still fire on internal@ExposeImplBinding-annotated types. - [FIR] Fix compatibility with IntelliJ
2026.1.3. - [FIR] Don't merge generated binding containers from
@ContributesInto*declarations as supertypes when aggregating contributions. - [IR] Fix graph extensions inheriting a farther ancestor's contribution-provider binding when a closer parent graph already owns a scoped binding for the same key.
- [IR] Fix dynamic graphs (
createDynamicGraph/createDynamicGraphFactory) sharing a single generated impl across call sites in different files. The shared impl was aprivate(on the JVM, package-private) nested class placed under one call site, so call sites in other packages failed at runtime withIllegalAccessError, and removing the owning file causedNoClassDefFoundError. Generated impls are now cached per-file. - [IR] Fix IR graph nodes eagerly resolving supertypes.
- [IR] Don't reserve an
InstanceFactoryfield for graph inputs unless it's needed. - [interop] Read
@IntoSet/@IntoMap/@MapKeymultibinding annotations from external Dagger modules.
Changes
- Promote
@GraphPrivateto stable. - Promote
@DefaultBindingto stable. - Promote
generateContributionProviders(and@ExposeImplBinding) to stable. - [gradle] Add missing experimental annotations to the Gradle plugin's analysis APIs. Sorry these were not meant to be stabilized yet!
- Build against Kotlin
2.4.0. Note the runtime artifacts still target Kotlin2.3.0and Metro supports a wide range of compiler versions. See the compatibility docs for a full table of compatible versions. - No longer test most Kotlin
2.4.0pre-release builds. Kotlin2.4.0-dev-2124is still tested because this appears to be roughly where IntelliJ platform 2026.1.x branched from. - Test Android Studio Quail 1 stable (
2026.1.1.8). - Test Android Studio Quail 2 canaries (
2026.1.2.4). - Test IntelliJ
2026.1.2. - Test IntelliJ
2026.1.3.
Contributors
Special thanks to the following contributors for contributing to this release!
Consider sponsoring Metro's development
Go Knicks!
What's Changed
- Update a few misc deps by @ZacSweers in #2301
- Clean up module-info dupe warnings by @ZacSweers in #2304
- More publishing cleanup by @ZacSweers in #2303
- Update dependency dev.zacsweers.metro to v1.1.1 by @renovate[bot] in #2305
- Update dependency dev.zacsweers.metro:compiler to v1.1.1 by @renovate[bot] in #2306
- Update ktor monorepo to v3.5.0 by @renovate[bot] in #2308
- Add a test for generated graph extensions by @kevinguitar in #2307
- Update dependency com.autonomousapps:gradle-testkit-support to v0.25 by @renovate[bot] in #2309
- Update dependency zensical to v0.0.42 by @renovate[bot] in #2313
- Update wire to v6.4.0 by @renovate[bot] in #2314
- Fix minor typo in ExposeImplBinding docs by @WhosNickDoglio in #2315
- Update IDE version mappings by @ZacSweers in #2312
- Add missing kotlin syntax in
aggregation.mdcode block by @SimonMarquis in #2317 - Fix Markdown links in
injection-types.mdby @SimonMarquis in #2316 - Fix missing empty line for proper markdown rendering by @SimonMarquis in #2321
- Make MetroFirTypeResolver's factory and caching methods public by @kevinguitar in #2322
- Update dependency io.insert-koin.compiler.plugin to v1.0.0 by @renovate[bot] in #2329
- Update dependency zensical to v0.0.43 by @renovate[bot] in #2325
- Update junit-framework monorepo to v6.1.0 by @renovate[bot] in #2328
- Update dependency androidx.tracing:tracing-wire-desktop to v2.0.0-alpha08 by @renovate[bot] in #2327
- Update dependency com.slack.foundry:better-gradle-properties to v0.35.2 by @renovate[bot] in #2323
- Update dependency com.autonomousapps:gradle-testkit-support to v0.26 by @renovate[bot] in #2310
- Update dependency click to v8.4.0 by @renovate[bot] in #2319
- Update dependency androidx.lint:lint-gradle to v1.0.0-rc01 by @renovate[bot] in #2326
- Update IDE version mappings by @ZacSweers in #2331
- Update IDE version mappings by @ZacSweers in #2335
- Update plugin gradleTestRetry to v1.6.5 by @renovate[bot] in #2337
- Update dependency click to v8.4.1 by @renovate[bot] in #2336
- Update AGP to v9 by @renovate[bot] in #2274
- Switch to WAL + non-synchronization in IC by @ZacSweers in #2343
- Fix dynamic class caching across files by @ZacSweers in #2344
- Remove secondary topo sort by @ZacSweers in #2345
- Update plugin com.gradle.develocity to v4.4.2 by @renovate[bot] in #2346
- Add modes for reducing generated field name types by @ZacSweers in #2347
- Update ksp monorepo to v2.3.9 by @renovate[bot] in #2351
- Update IDE version mappings by @ZacSweers in #2352
- Update plugin shadow to v9.4.2 by @renovate[bot] in #2355
- Update dependency tornado to v6.5.6 by @renovate[bot] in #2353
- Update dependency com.facebook:ktfmt to v0.63 by @renovate[bot] in #2356
- Update dependency com.facebook:ktfmt to v0.63 by @renovate[bot] in #2357
- Fix local bindings are not replaced with contribution providers by @jonamireh in #2349
- Lazily compute cached hashCode and toString renders by @ZacSweers in #2359
- Test Kotlin 2.4.0-RC2 by @ZacSweers in #2360
- Update IDE version mappings by @ZacSweers in #2362
- Add Hilt
@InstallIninterop by @ZacSweers in #2361 - Remove eager lookups of some GraphNode props by @ZacSweers in #2358
- Update IDE version mappings by @ZacSweers in #2363
- Propagate inline status from provides functions by @ZacSweers in #2365
- Fix bootstrap fetch by @ZacSweers in #2366
- Update dependency mkdocs-git-revision-date-localized-plugin to v1.5.3 by @renovate[bot] in #2368
- Update IDE version mappings by @ZacSweers in #2371
- Update actions/checkout digest to df4cb1c by @renovate[bot] in #2372
- Update plugin buildConfig to v6.0.10 by @renovate[bot] in #2373
- Update dependency dev.zacsweers.kctfork:core to v0.13.0 by @renovate[bot] in #2374
- Update dependency dev.zacsweers.kctfork:ksp to v0.13.0 by @renovate[bot] in #2375
- Update kct to v0.13.0 by @renovate[bot] in #2377
- Add primitive factories + inline provider bodies support by @ZacSweers in #2376
- Move main to 2.4.0 by @ZacSweers in #2378
- Widen factory create() return types + provider inlining docs by @ZacSweers in #2381
- Add compiler stats to reports by @ZacSweers in #2367
- Use backing fields in a few places by @ZacSweers in #2382
- Use new declaration finder APIs by @ZacSweers in #2383
- Update IDE version mappings by @ZacSweers in #2385
- Regen tests by @ZacSweers in #2387
- Update IDE tests by @ZacSweers in #2384
- Loosen nonPublicContributionSeverity warning if contribution providers are enabled by @ZacSweers in #2388
- Update dependency zensical to v0.0.44 by @renovate[bot] in #2389
- Test AS Quail 2 by @ZacSweers in #2390
- Add bounded backoff to the native Lock by @ZacSweers in #2391
- Update poko + disable by @ZacSweers in #2392
- Add config for new native lock by @ZacSweers in #2394
- Fix typo in @BINDS kdoc by @kevinguitar in #2395
- Update IDE version mappings by @ZacSweers in #2398
- Read @IntoSet/@IntoMap/@mapkey from external Dagger modules by @eygraber in #2397
- Move SpinLock to commonMain by @ZacSweers in #2399
- Improve IDE kotlinc version resolution by @ZacSweers in #2400
- Improve SpinLock tests by @ZacSweers in #2401
- Releasing cleanups by @ZacSweers in #2402
- Split out backoff testing by @ZacSweers in #2403
- Remove js(IR) flag by @ZacSweers in #2404
- Idea by @ZacSweers in #2405
- Add basic plugin enabled wiring by @ZacSweers in #2408
- Clean up options + support custom options by @ZacSweers in #2409
- Avoid merging binding containers as supertypes by @ZacSweers in #2410
- Update IDE version mappings by @ZacSweers in #2411
- Update dependency tornado to v6.5.7 by @renovate[bot] in #2413
- Update okhttp monorepo to v5.4.0 by @renovate[bot] in #2414
- Refactor out metro-common and metro options for reuse by @ZacSweers in #2412
- Promote generateContributionProviders to stable by @ZacSweers in #2415
- Update dependency zensical to v0.0.45 by @renovate[bot] in #2416
- Rework DoubleCheck by @ZacSweers in #2417
- Promote a few APIs to stable by @ZacSweers in #2418
- Update circuit to v0.34.0 by @renovate[bot] in #2420
- Fix inlined access to non-visible class types by @ZacSweers in #2422
- Fix typo in Circuit integration documentation by @shenghaiyang in #2424
- Allow inline provider materialization to fail by @ZacSweers in #2425
New Contributors
- @WhosNickDoglio made their first contribution in #2315
- @SimonMarquis made their first contribution in #2317
- @eygraber made their first contribution in #2397
- @shenghaiyang made their first contribution in #2424
Full Changelog: 1.1.1...1.2.0