# Declaring Dependencies

version 9.6.0-20260330000154+0000

## Types of dependencies

There are three main types of dependencies in Gradle:

1. Module Dependencies: Refer to libraries from external repositories.

2. Project Dependencies: Refer to other projects in the same multi-project build.

3. File Dependencies: Refer to local files or directories, such as `.jar` or `.aar` files.

### 1. Module dependencies

Module dependencies are the most common dependencies. They refer to a published module by its coordinates (`group:name:version`).

Every dependency is added to a bucket configuration that defines its scope.

Use the single string `"group:name:version"` (you can also include classifier/extension if needed, e.g., `group:name:version:classifier@ext`):

build.gradle.kts

    dependencies {
        // 1) Regular module dependency using string notation (JAR)
        runtimeOnly("org.springframework:spring-core:2.5",
            "org.springframework:spring-aop:2.5")

        // 2) Regular module dependency with a config block
        runtimeOnly("org.hibernate:hibernate:3.0.5") {
            isTransitive = true
        }

        // 3) Classifier + extension (:resources@zip) — fetches a ZIP artifact instead of a JAR
        runtimeOnly("net.sf.docbook:docbook-xsl:1.75.2:resources@zip")

        // 4) Extension only (@aar) — Android AAR instead of JAR
        implementation("com.google.android.material:material:1.11.0@aar")
    }

build.gradle

    dependencies {
        // 1) Regular module dependency using string notation (JAR)
        runtimeOnly("org.springframework:spring-core:2.5",
            "org.springframework:spring-aop:2.5")

        // 2) Regular module dependency with a config block
        runtimeOnly("org.hibernate:hibernate:3.0.5") {
            transitive = true
        }

        // 3) Classifier + extension (:resources@zip) — fetches a ZIP artifact instead of a JAR
        runtimeOnly("net.sf.docbook:docbook-xsl:1.75.2:resources@zip")

        // 4) Extension only (@aar) — Android AAR instead of JAR
        implementation("com.google.android.material:material:1.11.0@aar")
    }

| The map notation is deprecated and will be removed in Gradle 10. Prefer the single-string form. For example: `runtimeOnly(group: 'org.springframework', name: 'spring-core', version: '2.5')`. Should be: `runtimeOnly('org.springframework:spring-core:2.5')`.

Module dependencies use the `ExternalModuleDependency` and `DependencyHandler` APIs. These APIs provide expose properties and configuration methods for defining dependencies such a `transitive`, `because`, and a `version {}` block for `strictly`, `prefer`, and `reject`.

### 2. Project dependencies

Project dependencies allow you to reference other projects within a multi-project Gradle build.

This is useful for organizing large projects into smaller, modular components:

web-service/build.gradle.kts

    dependencies {
        implementation(project(":utils"))
        implementation(project(":api"))
    }

web-service/build.gradle

    dependencies {
        implementation project(':utils')
        implementation project(':api')
    }

Gradle uses the `project()` function to define a project dependency. This function takes the relative path to the target project within the build. The path is typically defined using a colon (`:`) to separate different levels of the project structure.

Project dependencies are automatically resolved such that the dependent project is always built before the project that depends on it.

#### Type-safe project dependencies

Type-safe project accessors are an incubating feature which must be enabled explicitly. Implementation may change at any time.

To add support for type-safe project accessors, add `enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")` this to your `settings.gradle(.kts)` file:

settings.gradle.kts

    enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")

settings.gradle

    enableFeaturePreview 'TYPESAFE_PROJECT_ACCESSORS'

One downside of using the `project(":some:path")` notation is the need to remember project paths for dependencies. Moreover, changing a project path requires manually updating every occurrence, increasing the risk of missing one.

Instead, the experimental type-safe project accessors API provides IDE completion, making it easier to declare dependencies:

web-service/build.gradle.kts

    dependencies {
        implementation(projects.utils)
        implementation(projects.api)
    }

web-service/build.gradle

    dependencies {
        implementation projects.utils
        implementation projects.api
    }

With this API, incorrectly specified projects in Kotlin DSL scripts trigger compilation errors, helping you avoid missed updates.

Project accessors are based on project paths. For instance, the path `:commons:utils:some:lib` becomes `projects.commons.utils.some.lib`, while kebab-case (`some-lib`) and snake-case (`some_lib`) are converted to camel case: `projects.someLib`.

### 3. File dependencies

File dependencies allow you to include external JARs or other files directly into your project by referencing their file paths. File dependencies also allow you to add a set of files directly to a configuration without using a repository.

| File dependencies are generally discouraged. Instead, prefer declaring dependencies on an external repository, or if necessary, declaring a maven or ivy repository using a `file://` URL.

File dependencies are unique because they represent a direct reference to files on the filesystem without any associated metadata, such as transitive dependencies, origin, or author information.

build.gradle.kts

    configurations {
        create("antContrib")
        create("externalLibs")
        create("deploymentTools")
    }

    dependencies {
        "antContrib"(files("ant/antcontrib.jar"))
        "externalLibs"(files("libs/commons-lang.jar", "libs/log4j.jar"))
        "deploymentTools"(fileTree("tools") { include("*.exe") })
    }

build.gradle

    configurations {
        antContrib
        externalLibs
        deploymentTools
    }

    dependencies {
        antContrib files('ant/antcontrib.jar')
        externalLibs files('libs/commons-lang.jar', 'libs/log4j.jar')
        deploymentTools(fileTree('tools') { include '*.exe' })
    }

In this example, each dependency explicitly specifies its location within the file system. Common methods for referencing these files include:

- `Project.files()`: Accepts one or more file paths directly.

- `ProjectLayout.files()`: Accepts one or more file paths directly.

- `Project.fileTree()`: Defines a directory and includes or excludes specific file patterns.

| The order of files in a `FileTree` is not guaranteed to be stable, even on the same computer. As a result, dependency configurations using `FileTree` may produce resolution results with varying order, which can impact the cacheability of tasks that use these results as inputs. To ensure more predictable and stable behavior, it is recommended to use the simpler `files` method where possible.

Alternatively, you can use a flat directory repository to specify the source directory for multiple file dependencies.

Ideally, you should use Maven or Ivy repository with a local URL:

    repositories {
        maven {
            url = 'file:///path/to/local/files' // Replace with your actual path
        }
    }

To add files as dependencies, pass a file collection to the configuration:

build.gradle.kts

    dependencies {
        runtimeOnly(files("libs/a.jar", "libs/b.jar"))
        runtimeOnly(fileTree("libs") { include("*.jar") })
    }

build.gradle

    dependencies {
        runtimeOnly files('libs/a.jar', 'libs/b.jar')
        runtimeOnly fileTree('libs') { include '*.jar' }
    }

Note that file dependencies are not included in the published dependency descriptor for your project. However, they are available in transitive dependencies within the same build, meaning they can be used within the current build but not outside it.

You should specify which tasks produce the files for a file dependency. Otherwise, the necessary tasks might not run when you depend on them transitively from another project:

build.gradle.kts

    dependencies {
        implementation(files(layout.buildDirectory.dir("classes")) {
            builtBy("compile")
        })
    }

    tasks.register("compile") {
        doLast {
            println("compiling classes")
        }
    }

    tasks.register("list") {
        val compileClasspath: FileCollection = configurations["compileClasspath"]
        dependsOn(compileClasspath)
        doLast {
            println("classpath = ${compileClasspath.map { file: File -> file.name }}")
        }
    }

build.gradle

    dependencies {
        implementation files(layout.buildDirectory.dir('classes')) {
            builtBy 'compile'
        }
    }

    tasks.register('compile') {
        doLast {
            println 'compiling classes'
        }
    }

    tasks.register('list') {
        FileCollection compileClasspath = configurations.compileClasspath
        dependsOn compileClasspath
        doLast {
            println "classpath = ${compileClasspath.collect { File file -> file.name }}"
        }
    }

    $ ./gradlew -q list

    compiling classes
    classpath = [classes]

## Gradle distribution-specific dependencies

Gradle provides special methods to declare dependencies on components that are part of the Gradle distribution. See more in the Gradle distribution-specific dependencies.

## Documenting dependencies

When declaring a dependency or a dependency constraint, you can provide a reason to clarify why the dependency is included. This helps make your build script and the dependency insight report easier to interpret:

build.gradle.kts

    plugins {
        `java-library`
    }

    repositories {
        mavenCentral()
    }

    dependencies {
        implementation("org.ow2.asm:asm:7.1") {
            because("we require a JDK 9 compatible bytecode generator")
        }
    }

build.gradle

    plugins {
        id 'java-library'
    }

    repositories {
        mavenCentral()
    }

    dependencies {
        implementation('org.ow2.asm:asm:7.1') {
            because 'we require a JDK 9 compatible bytecode generator'
        }
    }

In this example, the `because()` method provides a reason for including the `asm` library, which helps explain its purpose in the context of the build:

    $ ./gradlew -q dependencyInsight --dependency asm

    org.ow2.asm:asm:7.1
      Variant compile:
        | Attribute Name                 | Provided | Requested    |
        |--------------------------------|----------|--------------|
        | org.gradle.status              | release  |              |
        | org.gradle.category            | library  | library      |
        | org.gradle.libraryelements     | jar      | classes      |
        | org.gradle.usage               | java-api | java-api     |
        | org.gradle.dependency.bundling |          | external     |
        | org.gradle.jvm.environment     |          | standard-jvm |
        | org.gradle.jvm.version         |          | 11           |
       Selection reasons:
          - Was requested: we require a JDK 9 compatible bytecode generator

    org.ow2.asm:asm:7.1
    \--- compileClasspath

    A web-based, searchable dependency report is available by adding the --scan option.