Gradle Version Catalogs: порядок в зависимостях через libs.versions.toml
В крупном Gradle-проекте одна и та же проблема воспроизводится снова и снова: версия библиотеки прописана в одном модуле, другая версия той же библиотеки — в другом, и через полгода никто не помнит, почему они расходятся. Version catalogs — официальный механизм Gradle для решения этой проблемы. Он централизует управление зависимостями, добавляет типобезопасность и снижает вероятность конфликтов.
Что такое Version Catalog
Version catalog — это файл gradle/libs.versions.toml, в котором описаны все зависимости проекта: версии, координаты библиотек, плагины и группы зависимостей (bundles). Из этого файла Gradle генерирует типобезопасные аксессоры — вместо строки "org.codehaus.groovy:groovy:3.0.5" в build-скрипте пишется libs.groovy.core.
Основные преимущества:
- Все зависимости видны в одном месте — удобно при code review и аудите
- Опечатки в именах библиотек превращаются в ошибки компиляции, а не в runtime-проблемы
- IDE даёт автодополнение по каталогу
- Версию можно менять в одном месте — она обновляется во всех модулях
Структура libs.versions.toml
Файл состоит из четырёх секций.
versions
Именованные версии, на которые ссылаются библиотеки:
[versions]
groovy = "3.0.5"
kotlin = "2.3.20"
commons-lang3 = { strictly = "[3.8, 4.0[", prefer = "3.9" }
Поддерживаются rich version constraints: require, strictly, prefer, reject.
libraries
Координаты зависимостей. Три способа записи:
[libraries]
# Краткая форма
my-lib = "com.example:mylib:1.4"
# С отдельной ссылкой на версию
groovy-core = { module = "org.codehaus.groovy:groovy", version.ref = "groovy" }
# С rich constraints
commons-lang3 = { group = "org.apache.commons", name = "commons-lang3",
version = { strictly = "[3.8, 4.0[", prefer = "3.9" } }
bundles
Группы библиотек, которые часто добавляются вместе:
[bundles]
groovy = ["groovy-core", "groovy-json", "groovy-nio"]
В build-скрипте вместо трёх строк — одна:
dependencies {
implementation(libs.bundles.groovy)
}
plugins
Плагины с версиями:
[plugins]
versions = { id = "com.github.ben-manes.versions", version = "0.45.0" }
android-application = { id = "com.android.application", version.ref = "agp" }
Как использовать в build-скриптах
Gradle автоматически генерирует аксессоры по имени каталога. Дефисы в именах заменяются точками:
// build.gradle.kts
dependencies {
implementation(libs.groovy.core)
implementation(libs.commons.lang3)
testImplementation(libs.bundles.testing)
}
plugins {
alias(libs.plugins.versions)
alias(libs.plugins.android.application)
}
Миграция с прямых версий
Типичный сценарий перехода:
- Создать файл
gradle/libs.versions.toml - Перенести версии в секцию
[versions] - Описать все зависимости в
[libraries], сослаться на версии черезversion.ref - В build-скриптах заменить строковые координаты на
libs.*аксессоры - Для плагинов заменить
id("...") version "..."наalias(libs.plugins.*)
Для проектов с несколькими модулями файл лежит в корне, все модули обращаются к одному каталогу.
Несколько каталогов
Если нужна разбивка по контексту (например, отдельный каталог для тестовых зависимостей или внутренних инструментов):
// settings.gradle.kts
dependencyResolutionManagement {
versionCatalogs {
create("testLibs") {
from(files("gradle/test.versions.toml"))
}
create("tools") {
from(files("gradle/tools.versions.toml"))
}
}
}
В build-скриптах доступны libs.*, testLibs.* и tools.*.
Публикация каталога для нескольких проектов
Если несколько репозиториев должны использовать общий набор версий, каталог можно опубликовать как Maven-артефакт:
// build.gradle.kts (в репозитории-каталоге)
plugins {
`version-catalog`
`maven-publish`
}
catalog {
versionCatalog {
from(files("gradle/libs.versions.toml"))
}
}
Потребитель подключает его в settings.gradle.kts:
versionCatalogs {
create("libs") {
from("com.mycompany:catalog:1.0")
}
}
Важные ограничения
Version catalog декларирует запрошенные версии, но не принудительно их применяет. Gradle по-прежнему может выбрать другую версию из-за конфликтов в графе зависимостей. Для жёсткого pinning используйте strictly или платформы (BOM).
TOML-формат не поддерживает classifiers, artifact types (@aar, @zip), exclude rules и capabilities. Для classifiers — variantOf() в build-скрипте:
implementation(variantOf(libs.my.lib) { classifier("test-fixtures") })
В buildSrc каталог не подхватывается автоматически — нужен явный импорт в buildSrc/settings.gradle.kts.
Кому это нужно
Version catalogs полезны в первую очередь для:
- Multi-module проектов, где одни и те же зависимости используются в нескольких модулях
- Команд, которым важен контроль версий при code review
- Организаций с несколькими репозиториями, которые должны использовать согласованный набор библиотек
Для одномодульного небольшого проекта с 10 зависимостями усложнять build-конфигурацию каталогом не обязательно — прямые строки вполне читаемы. Переход имеет смысл, когда управление версиями становится отдельной операционной задачей.
Источник: официальная документация Gradle — docs.gradle.org. Актуальные примеры и поддерживаемые форматы — в официальной документации по версии Gradle вашего проекта.