# Managing Dependency Configurations

## What is a configuration?

Every dependency declared for a Gradle project applies to a specific scope. For example some dependencies should be used for compiling source code whereas others only need to be available at runtime. Gradle represents the scope of a dependency with the help of a Configuration. Every configuration can be identified by a unique name.

Many Gradle plugins add pre-defined configurations to your project. The Java plugin, for example, adds configurations to represent the various classpaths it needs for source code compilation, executing tests and the like. See the Java plugin chapter for an example. The sections above demonstrate how to declare dependencies for different use cases.

Figure 1. Configurations use declared dependencies for specific purposes

For more examples on the usage of configurations to navigate, inspect and post-process metadata and artifacts of assigned dependencies, see Working with Dependencies.

## Defining custom configurations

You can define configurations yourself, so-called custom configurations. A custom configuration is useful for separating the scope of dependencies needed for a dedicated purpose.

Let’s say you wanted to declare a dependency on the Jasper Ant task for the purpose of pre-compiling JSP files that should not end up in the classpath for compiling your source code. It’s fairly simple to achieve that goal by introducing a custom configuration and using it in a task.

Example 1. Declaring and using a custom configuration
build.gradle

    configurations {
        jasper
    }

    repositories {
        mavenCentral()
    }

    dependencies {
        jasper 'org.apache.tomcat.embed:tomcat-embed-jasper:9.0.2'
    }

    task preCompileJsps {
        doLast {
            ant.taskdef(classname: 'org.apache.jasper.JspC',
                        name: 'jasper',
                        classpath: configurations.jasper.asPath)
            ant.jasper(validateXml: false,
                       uriroot: file('src/main/webapp'),
                       outputDir: file("$buildDir/compiled-jsps"))
        }
    }

build.gradle.kts

    val jasper by configurations.creating

    repositories {
        mavenCentral()
    }

    dependencies {
        jasper("org.apache.tomcat.embed:tomcat-embed-jasper:9.0.2")
    }

    tasks.register("preCompileJsps") {
        doLast {
            ant.withGroovyBuilder {
                "taskdef"("classname" to "org.apache.jasper.JspC",
                          "name" to "jasper",
                          "classpath" to jasper.asPath)
                "jasper"("validateXml" to false,
                         "uriroot" to file("src/main/webapp"),
                         "outputDir" to file("$buildDir/compiled-jsps"))
            }
        }
    }

A project’s configurations are managed by a `configurations` object. Configurations have a name and can extend each other. To learn more about this API have a look at ConfigurationContainer.

## Inheriting dependencies from other configurations

A configuration can extend other configurations to form an inheritance hierarchy. Child configurations inherit the whole set of dependencies declared for any of its superconfigurations.

Configuration inheritance is heavily used by Gradle core plugins like the Java plugin. For example the `testImplementation` configuration extends the `implementation` configuration. The configuration hierarchy has a practical purpose: compiling tests requires the dependencies of the source code under test on top of the dependencies needed write the test class. A Java project that uses JUnit to write and execute test code also needs Guava if its classes are imported in the production source code.

Figure 2. Configuration inheritance provided by the Java plugin

Under the covers the `testImplementation` and `implementation` configurations form an inheritance hierarchy by calling the method Configuration.extendsFrom(org.gradle.api.artifacts.Configuration[]). A configuration can extend any other configuration irrespective of its definition in the build script or a plugin.

Let’s say you wanted to write a suite of smoke tests. Each smoke test makes a HTTP call to verify a web service endpoint. As the underlying test framework the project already uses JUnit. You can define a new configuration named `smokeTest` that extends from the `testImplementation` configuration to reuse the existing test framework dependency.

Example 2. Extending a configuration from another configuration
build.gradle

    configurations {
        smokeTest.extendsFrom testImplementation
    }

    dependencies {
        testImplementation 'junit:junit:4.12'
        smokeTest 'org.apache.httpcomponents:httpclient:4.5.5'
    }

build.gradle.kts

    val smokeTest by configurations.creating {
        extendsFrom(configurations.testImplementation.get())
    }

    dependencies {
        testImplementation("junit:junit:4.12")
        smokeTest("org.apache.httpcomponents:httpclient:4.5.5")
    }