Home > Developer Guide > Guides > Gradle Version Catalogs + BOM
Gradle Version Catalogs with Bill of Materials (BOM)
Purpose: Definitive guide to correctly using Gradle version catalogs with BOM dependencies
Context: Discovered during PR #269 Firebase BOM debugging - syntax WAS correct, library availability was the issue
Key Insight: Version catalogs + BOMs work perfectly together when configured correctly
Overview
What Are Version Catalogs?
Gradle Version Catalogs provide centralized dependency management in gradle/libs.versions.toml:
Benefits:
- Single source of truth for dependency versions
- Type-safe accessors in build scripts (
libs.firebase.auth) - IDE autocomplete support
- Easier dependency updates across multi-module projects
What Are BOMs?
Bill of Materials (BOM) is a special Maven artifact that declares compatible versions of related libraries:
Benefits:
- Guaranteed compatible library versions
- No need to specify individual library versions
- Simplified dependency management
- Transitive version resolution
The Challenge
Combining version catalogs with BOMs requires specific syntax. During PR #269 debugging, we initially suspected the syntax was wrong when builds failed, but the real issue was library availability in the BOM.
This guide documents the CORRECT patterns so future developers don’t waste hours debugging.
The Correct Pattern
Version Catalog Configuration
File: gradle/libs.versions.toml
[versions]
# BOM version declared here
firebase-bom = "33.0.0"
compose-bom = "2025.11.00"
[libraries]
# BOM entry WITH version
firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "firebase-bom" }
# Individual libraries WITHOUT versions (BOM provides them)
firebase-auth = { group = "com.google.firebase", name = "firebase-auth" }
firebase-firestore = { group = "com.google.firebase", name = "firebase-firestore" }
firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics" }
# Compose BOM WITH version
compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
# Compose libraries WITHOUT versions (BOM provides them)
compose-material3 = { group = "androidx.compose.material3", name = "material3" }
compose-ui = { group = "androidx.compose.ui", name = "ui" }
compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }Build Script Usage
File: app/build.gradle.kts
dependencies {
// Import BOM using platform()
implementation(platform(libs.firebase.bom))
implementation(platform(libs.compose.bom))
// Use individual libraries (versions from BOM)
implementation(libs.firebase.auth)
implementation(libs.firebase.firestore)
implementation(libs.firebase.analytics)
implementation(libs.compose.material3)
implementation(libs.compose.ui)
debugImplementation(libs.compose.ui.tooling)
}Key Points:
- BOM entry: Must have
version.refor explicit version - Individual libraries: Must NOT have versions
- Must use
platform()wrapper for BOM entries - Must use object notation (
{ group = ..., name = ... }), NOT string notation
Why This Works
Gradle’s BOM Resolution Process
-
platform(libs.firebase.bom)declaration:- Gradle imports Firebase BOM artifact
- BOM contains version constraints for all Firebase libraries
-
implementation(libs.firebase.auth)declaration:- Gradle looks for
com.google.firebase:firebase-authartifact - No version specified in version catalog
- Gradle checks BOM for version constraint
- BOM provides version (e.g.,
22.1.0) - Gradle resolves to
com.google.firebase:firebase-auth:22.1.0
- Gradle looks for
-
Version consistency:
- All libraries managed by BOM get compatible versions
- No version conflicts between Firebase libraries
- Transitive dependencies also managed by BOM
Common Mistakes
Mistake 1: Using String Notation for BOM Libraries
Wrong:
[libraries]
firebase-auth = "com.google.firebase:firebase-auth" # ❌ String notationCorrect:
[libraries]
firebase-auth = { group = "com.google.firebase", name = "firebase-auth" } # ✅ Object notationWhy It Fails:
String notation in version catalogs requires a version (e.g., "group:artifact:version"). BOM-managed dependencies can’t use string notation because they have no version.
Mistake 2: Specifying Versions for BOM-Managed Libraries
Wrong:
[versions]
firebase-auth = "22.1.0" # ❌ Don't specify versions for BOM-managed deps
[libraries]
firebase-auth = { group = "com.google.firebase", name = "firebase-auth", version.ref = "firebase-auth" }Correct:
[libraries]
firebase-auth = { group = "com.google.firebase", name = "firebase-auth" } # ✅ No versionWhy It Fails: Specifying a version overrides the BOM. This defeats the purpose of using a BOM and can cause version conflicts.
Mistake 3: Forgetting platform() Wrapper
Wrong:
dependencies {
implementation(libs.firebase.bom) # ❌ Missing platform()
implementation(libs.firebase.auth)
}Correct:
dependencies {
implementation(platform(libs.firebase.bom)) # ✅ Wrapped in platform()
implementation(libs.firebase.auth)
}Why It Fails:
Without platform(), Gradle treats the BOM as a regular library dependency instead of a constraint provider. Individual libraries won’t get versions from the BOM.
Mistake 4: Referencing Libraries Not in the BOM
Wrong:
[libraries]
firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version = "34.6.0" }
firebase-auth-ktx = { group = "com.google.firebase", name = "firebase-auth-ktx" } # ❌ Not in BOM 34.x!Error:
Could not find com.google.firebase:firebase-auth-ktx:.
^
Empty version string
Why It Fails:
Firebase BOM 34.0.0+ removed all -ktx libraries. The version catalog syntax is correct, but the library doesn’t exist in the BOM.
Solution:
Either use BOM 33.x (which includes -ktx) or remove -ktx suffix for BOM 34.x+.
Related: Firebase KTX Deprecation Guide
Advanced Patterns
Pattern 1: Multiple BOMs in One Project
Scenario: Using Firebase BOM and Compose BOM together
[versions]
firebase-bom = "33.0.0"
compose-bom = "2025.11.00"
[libraries]
firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "firebase-bom" }
compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
firebase-auth = { group = "com.google.firebase", name = "firebase-auth" }
compose-material3 = { group = "androidx.compose.material3", name = "material3" }dependencies {
implementation(platform(libs.firebase.bom))
implementation(platform(libs.compose.bom))
implementation(libs.firebase.auth)
implementation(libs.compose.material3)
}Works perfectly! Each BOM manages its own set of libraries.
Pattern 2: Mixing BOM and Non-BOM Dependencies
Scenario: Some libraries from BOM, others specified explicitly
[versions]
firebase-bom = "33.0.0"
retrofit = "2.9.0"
[libraries]
firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "firebase-bom" }
firebase-auth = { group = "com.google.firebase", name = "firebase-auth" } # From BOM
retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" } # Explicit versiondependencies {
implementation(platform(libs.firebase.bom))
implementation(libs.firebase.auth) // Version from BOM
implementation(libs.retrofit) // Explicit version
}Works great! BOM and non-BOM dependencies coexist happily.
Pattern 3: BOM Version Overrides (Advanced)
Scenario: Need specific version of one library, but use BOM for others
dependencies {
implementation(platform(libs.firebase.bom))
// Use BOM versions for most libraries
implementation(libs.firebase.auth)
implementation(libs.firebase.firestore)
// Override specific library version (use with caution!)
implementation("com.google.firebase:firebase-analytics:21.5.0") // Explicit version
}⚠️ Warning: Overriding BOM versions can cause compatibility issues. Only do this if you know what you’re doing.
Troubleshooting
Build Fails with “Could not find X:.”
Symptom:
Could not find com.google.firebase:firebase-auth:.
^
Empty version string
Diagnosis Steps:
-
Check BOM declaration:
grep "firebase-bom" gradle/libs.versions.tomlShould have a version:
firebase-bom = "33.0.0" -
Check platform() usage:
grep "platform.*firebase" app/build.gradle.ktsShould have:
implementation(platform(libs.firebase.bom)) -
Check library exists in BOM:
- Visit Maven Central
- Open BOM POM file for your version
- Search for the library name
-
Common causes:
- Library doesn’t exist in that BOM version (e.g.,
-ktxin BOM 34.x) - Typo in library name
- Missing
platform()wrapper - BOM version not specified in version catalog
- Library doesn’t exist in that BOM version (e.g.,
IDE Shows “Cannot Resolve Symbol” for libs.X
Symptom:
IntelliJ/Android Studio can’t resolve libs.firebase.auth
Solutions:
-
Sync Gradle:
- File > Sync Project with Gradle Files
- Or click the “Sync Now” banner
-
Invalidate Caches:
- File > Invalidate Caches / Restart
- Select “Invalidate and Restart”
-
Check version catalog syntax:
./gradlew checkLibsVersions # If you have this task -
Verify file location: Version catalog must be at
gradle/libs.versions.toml(notgradle/libs.versions.ymlor other location)
Versions from BOM Don’t Match Expectations
Symptom: Expected version X, but Gradle resolved version Y
Diagnosis:
./gradlew app:dependencies --configuration releaseRuntimeClasspath | grep firebaseLook for constraint sources:
com.google.firebase:firebase-auth:22.1.0
variant "runtime" [
org.gradle.category = library
org.gradle.status = release
]
via constraint: com.google.firebase:firebase-bom:33.0.0 # ← Source of version
Common causes:
- Wrong BOM version: Check
[versions]in version catalog - Version override: Search build files for explicit versions
- Transitive dependency: Another library depends on different Firebase version
Real-World Example: PR #269 Debugging
The Situation
Goal: Update Gradle dependencies to latest versions
Changes Made:
- Updated Firebase BOM from 33.0.0 to 34.6.0
- Moved Firebase dependencies to version catalog
- Used correct syntax (object notation, no versions)
Result:
Could not find com.google.firebase:firebase-analytics-ktx:.
Could not find com.google.firebase:firebase-crashlytics-ktx:.
The Investigation
Attempted Fixes (all failed):
- Fixed Compose BOM syntax (unrelated)
- Added
firebase-crashlytics-ktxto version catalog (didn’t help) - Fixed KSP version (unrelated)
- Downgraded Firebase BOM to 34.3.0 (still failed)
- Cleared Gradle caches multiple times (didn’t help)
The Breakthrough:
Compared with working main branch:
- Main uses Firebase BOM 33.0.0
- Main uses hardcoded strings, not version catalog
- Suspected version catalog was the issue
Further Investigation:
- Researched Gradle docs (syntax was correct)
- Researched Stack Overflow (conflicting advice)
- Found GitHub issue #17117 (confirmed pattern works)
- Checked Firebase release notes → KTX deprecated in BOM 34.0.0!
The Real Problem
Not a version catalog issue! The syntax was correct all along.
The actual problem:
- Firebase BOM 34.0.0+ removed
-ktxlibraries - Version catalog referenced
firebase-auth-ktx(doesn’t exist in BOM 34.x) - Gradle correctly looked for versions in BOM, found nothing → empty string
The Solution
Option A: Stay on BOM 33.0.0 (chosen for PR #269)
implementation(platform("com.google.firebase:firebase-bom:33.0.0"))
implementation("com.google.firebase:firebase-auth-ktx")Option B: Migrate to BOM 34.x without -ktx (future work)
implementation(platform("com.google.firebase:firebase-bom:34.6.0"))
implementation("com.google.firebase:firebase-auth") // No -ktxLessons Learned
- Version catalog syntax WAS correct - don’t blame the tools first
- Check external dependencies - breaking changes in libraries can look like configuration issues
- Compare with known-working state - saved hours of debugging
- Read release notes - Firebase announced this change, we just didn’t see it initially
Related Documentation:
Best Practices
1. Always Use Object Notation for BOM Libraries
# ✅ Correct
firebase-auth = { group = "com.google.firebase", name = "firebase-auth" }
# ❌ Wrong
firebase-auth = "com.google.firebase:firebase-auth"2. Document BOM Versions in Comments
[versions]
# Last version with KTX support (July 2025 deprecation)
firebase-bom = "33.0.0"
# Latest stable Compose BOM (Nov 2025)
compose-bom = "2025.11.00"3. Group Related Dependencies
[libraries]
# Firebase BOM and dependencies
firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "firebase-bom" }
firebase-auth = { group = "com.google.firebase", name = "firebase-auth" }
firebase-firestore = { group = "com.google.firebase", name = "firebase-firestore" }
# Compose BOM and dependencies
compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
compose-material3 = { group = "androidx.compose.material3", name = "material3" }4. Use Bundles for Common Sets
[bundles]
firebase = ["firebase-auth", "firebase-firestore", "firebase-analytics"]
compose-ui = ["compose-ui", "compose-material3", "compose-ui-tooling"]dependencies {
implementation(platform(libs.firebase.bom))
implementation(libs.bundles.firebase) // All Firebase deps at once
}5. Verify BOM Contents Before Upgrading
Before upgrading a BOM version:
- Check release notes for breaking changes
- Visit Maven Central and review BOM POM file
- Verify all your dependencies still exist in new BOM
- Test in a separate branch before merging
External Resources
Official Gradle Documentation:
- Version Catalogs - Complete guide to version catalogs
- BOM Support - How Gradle handles BOMs
- Dependency Management - Overall dependency management
GitHub Issues:
- gradle/gradle#17117 - Version catalogs + BOMs discussion
Related Project Documentation:
- Firebase KTX Deprecation - Firebase-specific BOM changes
- PR #269 Debugging Session - Real-world debugging example
Summary
Key Takeaways:
- Version catalogs + BOMs work perfectly together when configured correctly
- Use object notation for BOM-managed dependencies
- Omit versions for individual libraries (BOM provides them)
- Must use
platform()wrapper for BOM entries - Verify library exists in BOM before assuming syntax issue
- This pattern is officially supported by Gradle
When Builds Fail:
- Don’t immediately blame version catalog syntax
- Check if libraries exist in the BOM version you’re using
- Compare with known-working configuration
- Read external dependency release notes
Status: Active - Pattern validated during PR #269 debugging
Last Updated: 2025-11-18 Related PRs: #269 (Gradle dependency updates) Week: 28