Repository navigation
New
- [metrox-viewmodel-compose] Add support for
linuxX64. - [FIR] Add the
diagnostic-levelcompiler option to change the severity of Metro diagnostics reported in FIR. It works like kotlinc's-Xwarning-levelbut can also lower errors and use IDE-only levels. See changing diagnostic severity. - [FIR/IC] Add the
function-inject-annotations-overridecompiler option to use dedicated annotations for top-level function injection. See custom function injection annotations. - [FIR/IR] Support context parameters and extension receivers on
@Providesfunctions and properties. Both are dependencies and can be qualified. - [Gradle] Add opt-in checks to find Metro contributions hidden from a graph's compile classpath. Run
checkMainMetroHiddenDependencies(i.e., on CI). It writes a report and fails if it finds hidden contributions.- Supports JVM and Android compilations, including JVM targets in KMP. See checking for hidden contributions.
- Also checks Hilt aggregation metadata when Hilt interop is enabled.
- Configure scope filters with
scopesin the experimentalmetro.hiddenDependenciesDSL. EnablecheckOnCompilein the same block to run each check automatically after its Kotlin compilation, including when compilation fails. Automatic checks are disabled by default and may become the default in a future release.
Enhancements
- [IR] Reduce generated code in graph extensions by reusing existing parent bindings when their contributions and resolved dependencies are unchanged. Objects constructed in a single extension can receive sets and maps from parent getters when the parent already uses those collections.
- [IR] Graphs no longer generate a private getter for a multibinding that only one site reads. That site builds the collection itself.
- Reads from graph extensions that reuse the multibinding count too.
- Multibindings with more than 25 contributions also keep a getter so they don't crowd their reader's method. You can configure that threshold with the new
multibinding-getter-thresholdcompiler option.
- [IR] When several graph extensions use the same binding, their nearest common ancestor now generates its construction code in a shared getter. This also applies when different classes in those extensions depend on the binding. Unscoped bindings still create a new instance on each call.
- [IR] When several accessors request the same key and return type, the first accessor holds the binding's code and the others call through to it.
- [IR] Graphs no longer store themselves in a field. Code that needs the graph reads
this, or the graph reference that a shard or switching provider already holds. - [IR] Generated code wraps instances in providers with
providerOf(). On JVM that's one static call.InstanceFactory.invoke()also loaded its companion and boxed the value class. - [IR] Provider lambdas that Metro generates are SAM-converted to
Providerdirectly. The inlineprovider()function they went through before added a type check and a second wrapper object at every site. - [IR] Each switching provider class numbers its bindings from zero. Shards used to switch on graph-wide IDs with gaps between them.
- [IR] Switching provider branches read the graph reference into a local when more than one branch needs it.
- [IR] Graph shard constructors read the graph from their constructor parameter. A shard drops its
graphfield when only its constructor used it. - [IR] Instance reads of
@Includesgraph accessors that returnProvider<T>or() -> Tcall the accessor directly. They used to cache a converted provider in a field or wrap the accessor in a new provider lambda.Lazyaccessors still cache their handle, so their value is computed once. - [IR/JVM] Fields in generated graphs, shards, and switching providers are now package-private on JVM. This reduces synthetic accessors.
- [IR/JVM] Generated code calls
@JvmStaticfunctions in objects and companion objects statically on JVM. This keeps companion classes out of the caller's constant pool. At runtime each call still goes through the companion, since the static method forwards to it. In a 500-module benchmark this made the generated graph classes 17% smaller. - [IR/JS] On JS, converting a
Providerto() -> Torsuspend () -> Tnow calls a small runtime helper. Each site used to generate its own wrapper lambda. - [IR/interop] Providers of absent
@BindsOptionalOfbindings use anInstanceFactorythat holdsOptional.empty()instead of generating a local lambda each time.
Fixes
- [FIR] Reduce redundant lookups when discovering contributed graph extension factories.
- [FIR] Fix accessor override status on Kotlin
2.5.0-dev-10106. - [FIR/IC] Avoid unnecessary recompilation of independent injected classes when generating contribution hints.
- [FIR/interop] Fix duplicate class errors during caused by Hilt interop generating hints for upstream modules.
- [FIR/IR/interop] Fix incremental builds not updating graphs when an upstream Hilt
@AggregatedDepsmarker changes or is removed. - [FIR/IR/Gradle] Fix false self-loop errors in
analyzeMetroGraphwhen one qualified map depends on another. - [IR] Fix a qualified request resolving to an unqualified
@Injectclass. A qualified optional binding now uses its default, and other qualified requests report a missing binding. - [IR] Fix member injection across modules when an injected member uses a generic base class's type parameter.
- [IR] Fix missing binding errors for accessors inherited from another module having no source location.
- [IR] Fix
MissingRuntimeCoroutineserrors for injected top-level functions pointing at0:0in a generated file. They're now reported on the function. - [IR] Fix declaration parents for copied default argument lambdas and callable references, including references inside generated provider wrappers.
- [IR] Include extension receivers in generated lambda function types, including set and map builder callbacks.
- [IR] Fix a compiler crash when injecting a provider of a single-entry
Map<Class<*>, V>withenableKClassToClassMapKeyInteropenabled. - [IR] Fix IR diagnostic reporting on Kotlin
2.5.0-dev-10106. - [IR] Fix graphs storing an
@Includesgraph parameter in two fields when the included graph has graph extensions. - [IR] Fix runtime tracing passing a contextual type that matches the binding's type. It's now
nullas documented. - [IR/IC] Fix stale graphs in incremental builds when a replacing binding container's
@ContributesToannotation is removed and restored. - [IR/native/circuit] Fix an
IrLinkageErrorin generatedSubCircuitUI factories on Kotlin/Native with Kotlin2.5.0-Beta1. - [compat] Fix Kotlin
2.5.0-Beta1selecting a compat implementation built for newer2.5.0dev builds. Kotlin Beta and RC releases now map to the dev compat implementation that matches their branch point. - [metrox-android] Fix
MetroAppComponentFactorycrashing with aClassCastExceptionwhen Android starts the app with a plainApplicationfor a full backup or restore.
Changes
- Build against Android SDK
37and AGP9.1.1. - Update Lifecycle dependencies to
2.11.0and JetBrains Compose to1.12.2. - [metrox-viewmodel/metrox-viewmodel-compose] Drop Apple x86_64 targets removed by upstream dependencies.
metrox-viewmodeldropsiosX64,macosX64,tvosX64, andwatchosX64.metrox-viewmodel-composedropsiosX64andmacosX64. - Update
androidx.annotationto1.11.0andandroidx.coreto1.19.1. - [compat] Test against Kotlin
2.5.0-dev-10106. - [FIR] Report a
@MapKeyon a member with no binding annotation as a dedicatedMAP_KEY_WITHOUT_INTO_MAPerror. If another tool binds the member into a map, lower it with thediagnostic-levelcompiler option or@Suppress. Binding declarations like@Provideskeep the existing error. - [FIR/interop] Report a
@MapKeyon a class with no Metro contribution annotation as a dedicatedMAP_KEY_WITHOUT_CONTRIBUTES_INTO_MAPerror. If another tool binds the class into a map, lower it to a warning with thediagnostic-levelcompiler option. - [FIR/IR/IC] Enable
omit-redundant-mirrorsby default on Kotlin 2.4.0 and newer to omit generated declaration mirrors when compiler metadata and declaration finders provide the same information. It remains disabled by default on older Kotlin versions. Disable it withcompilerOptions.disable("omit-redundant-mirrors")in themetroDSL. - [Gradle]
enableTopLevelFunctionInjectionis disabled by default for now on all Kotlin versions because it makes incremental builds recompile more files. If you use top-level function injection, enable it withenableTopLevelFunctionInjection.set(true)in themetroDSL. See incremental compilation perf docs. - Test Android Studio Rabbit 1 (
2026.2.1.8). - Test IntelliJ
2026.2.3. - Update to androidx.tracing
2.0.4. - Test against Kotlin
2.5.0-Beta2.
Contributors
Special thanks to the following contributors for contributing to this release!
Consider sponsoring Metro's development
What's Changed
- Update plugin com.gradle.develocity to v4.6.0 by @renovate[bot] in #2870
- Update to Gradle 9.8.0 by @ZacSweers in #2871
- Update IDE version mappings by @ZacSweers in #2875
- Fix member injection with superclass type param use by @agrosner in #2873
- Recompile graphs when upstream Hilt markers change by @ZacSweers in #2889
- Update plugin buildConfig to v6.1.2 by @renovate[bot] in #2883
- Update dependency Markdown to v3.11 - autoclosed by @renovate[bot] in #2880
- Update wire to v7.0.4 by @renovate[bot] in #2879
- Update dependency zensical to v0.0.65 by @renovate[bot] in #2877
- Update dependency com.android.tools:r8 to v9.4.26 by @renovate[bot] in #2876
- Add hidden dependency checker by @ZacSweers in #2881
- Report missing bindings for upstream accessors on the graph by @ZacSweers in #2885
- Update Metro bootstrap to v1.4.5 by @renovate[bot] in #2878
- Optimize predicate lookups + disable function inject by default by @ZacSweers in #2892
- Cache dependency graphs in hidden dependency checks by @joshfriend in #2897
- Update IDE version mappings by @ZacSweers in #2899
- Update dependency com.android.tools:r8 to v9.4.28 by @renovate[bot] in #2898
- Update dependency com.google.guava:guava to v33.7.2-jre by @renovate[bot] in #2901
- Update dependency com.google.googlejavaformat:google-java-format to v1.37.0 by @renovate[bot] in #2903
- Update dependency MarkupSafe to v3.0.4 by @renovate[bot] in #2907
- Update IntelliJ 2026.3 EAP test version by @ZacSweers in #2914
- Fix Circuit IR symbol ref by @ZacSweers in #2900
- API cleanups + omit redundant mirrors by @ZacSweers in #2905
- Update dependency com.android.tools:r8 to v9.5.22 by @renovate[bot] in #2910
- Update dependency zensical to v0.0.68 by @renovate[bot] in #2893
- Update dependency com.slack.foundry:better-gradle-properties to v0.37.0 by @renovate[bot] in #2911
- Fix duplicate hint gen for hilt by @ZacSweers in #2915
- Update wire to v7.1.0 by @renovate[bot] in #2895
- Test 2.5.0-dev-9169 + CI updates by @ZacSweers in #2916
- Workaround kotlinc IC issue with generated FIR files by @kevinguitar in #2908
- Update dependency org.junit:junit-bom to v6 by @renovate[bot] in #2918
- Revert "Update dependency org.junit:junit-bom to v6" by @ZacSweers in #2920
- Update Gradle to v9.8.1 by @renovate[bot] in #2922
- Update to ktfmt 0.65 by @ZacSweers in #2926
- Update dependency androidx.collection:collection to v1.7.0 by @renovate[bot] in #2924
- Update actions/setup-node action to v7.1.0 by @renovate[bot] in #2927
- Update dependency org.junit:junit-bom to v6 by @renovate[bot] in #2925
- Test 2.5.0-dev-10106 and map Kotlin prereleases to compat modules by @ZacSweers in #2930
- Fix Windows multiplatform sample compilation by @ZacSweers in #2934
- Update IDE version mappings by @ZacSweers in #2936
- Update dependency org.junit:junit-bom to v6 by @renovate[bot] in #2933
- Update dependency zensical to v0.0.69 - autoclosed by @renovate[bot] in #2931
- Reuse parent multibinding getters in children by @ZacSweers in #2937
- Update dependency org.ow2.asm:asm to v9.11 by @renovate[bot] in #2938
- Binding fingerprints by @ZacSweers in #2939
- Add diagnostic warning for MapKey without ContributesIntoMap by @wbonnefond in #2932
- Add diagnostic-level compiler option by @ZacSweers in #2941
- Various graph code gen size optimizations by @ZacSweers in #2942
- Update dependency com.slack.foundry:better-gradle-properties to v0.37.1 by @renovate[bot] in #2943
- Update IDE version mappings by @ZacSweers in #2944
- Reuse shared getters in parent graphs by @ZacSweers in #2945
- Update dependency pymdown-extensions to v12.2 by @renovate[bot] in #2946
- Fix MetroAppComponentFactory crash when Android creates a plain Application by @barq-al-layl in #2935
- Update dependency python to 3.15 by @renovate[bot] in #2947
- Add missing circuit web test by @ZacSweers in #2940
- Update IDE version mappings by @ZacSweers in #2950
- Preserve map qualifiers in graph reports by @ZacSweers in #2951
- Update IDE version mappings by @ZacSweers in #2952
- Update dependency zensical to v0.0.70 by @renovate[bot] in #2953
- Fix duplicated multibinding builders by @ZacSweers in #2957
- Update IDE version mappings by @ZacSweers in #2958
- Use structural identity for type keys and qualifiers by @ZacSweers in #2956
- IDEA publishing prep by @ZacSweers in #2955
- Android 37 + compose + lifecycle + targets update by @ZacSweers in #2959
- Update dependency Markdown to v3.11.1 by @renovate[bot] in #2960
- Update IDE version mappings by @ZacSweers in #2961
- Update dependency com.android.tools:r8 to v9.5.26 by @renovate[bot] in #2921
- Make regen faster by @ZacSweers in #2962
- Update tracing to v2.0.4 by @renovate[bot] in #2954
- Finish IDE releasing setup + cache-only find usages by @ZacSweers in #2963
- Update IDE version mappings by @ZacSweers in #2965
- Update dependency pymdown-extensions to v12.3 by @renovate[bot] in #2964
- Update compose.jb to v1.12.2 by @renovate[bot] in #2539
- Update IDE version mappings by @ZacSweers in #2969
- Don't resolve a qualified request from an unqualified @Inject class by @falqadi in #2966
- Allow reuse of optional binding getters too by @ZacSweers in #2976
- Add a suppressible MAP_KEY_WITHOUT_INTO_MAP diagnostic by @falqadi in #2970
- Update dependency com.slack.foundry:better-gradle-properties to v0.37.2 by @renovate[bot] in #2972
- Update dependency zensical to v0.0.71 by @renovate[bot] in #2971
- Update IDE version mappings by @ZacSweers in #2980
- Update IDE version mappings by @ZacSweers in #2982
- Update IDE version mappings by @ZacSweers in #2983
- Update IDE version mappings by @ZacSweers in #2985
- Update dependency Markdown to v3.11.2 by @renovate[bot] in #2987
- Update dependency pillow to v13 by @renovate[bot] in #2979
- Update dependency org.ow2.asm:asm to v9.11.1 by @renovate[bot] in #2981
- Update plugin com.gradle.develocity to v4.6.1 by @renovate[bot] in #2989
- Update Gradle to v9.8.2 by @renovate[bot] in #2988
- Hoist more shared binding creation by @ZacSweers in #2990
- Update dependency com.autonomousapps:gradle-testkit-support to v0.30 by @renovate[bot] in #2991
- Update plugin testkit to v0.21 by @renovate[bot] in #2992
- Update IDE version mappings by @ZacSweers in #2993
- Avoid generating unnecessary getters by @ZacSweers in #2994
- Test 2.5.0-Beta2 by @ZacSweers in #2997
- Update IDE version mappings by @ZacSweers in #3001
- Update IDE version mappings by @ZacSweers in #3003
- Update IDE version mappings by @ZacSweers in #3005
- Update dependency zensical to v0.0.72 by @renovate[bot] in #3004
- Update dependency com.squareup.okhttp3:okhttp to v5.5.1 by @renovate[bot] in #3000
- Update dependency python-dateutil to v3 by @renovate[bot] in #2999
- Update dependency tornado to v6.6 by @renovate[bot] in #2998
- Update dependency com.slack.foundry:better-gradle-properties to v0.37.3 by @renovate[bot] in #2995
- Update dependency com.android.tools:r8 to v9.5.28 by @renovate[bot] in #2986
- Update dependency mkdocs-material to v9.8.0 by @renovate[bot] in #3006
- Support context params & extensions on
@Providesdeclarations by @ZacSweers in #3008 - Fix flaky implicit-usage IDE test by @ZacSweers in #3012
New Contributors
- @agrosner made their first contribution in #2873
- @joshfriend made their first contribution in #2897
- @wbonnefond made their first contribution in #2932
- @barq-al-layl made their first contribution in #2935
- @falqadi made their first contribution in #2966
Full Changelog: 1.4.5...1.5.0