[gradle] What's the difference between implementation and compile in Gradle?

After updating to Android Studio 3.0 and creating a new project, I noticed that in build.gradle there is a new way to add new dependencies instead of compile there is implementation and instead of testCompile there is testImplementation.

Example:

 implementation 'com.android.support:appcompat-v7:25.0.0'
 testImplementation 'junit:junit:4.12'

instead of

 compile 'com.android.support:appcompat-v7:25.0.0'
 testCompile 'junit:junit:4.12'

What's the difference between them and what should I be using?

The answer is


Brief Solution:

The better approach is to replace all compile dependencies with implementation dependencies. And only where you leak a module’s interface, you should use api. That should cause a lot less recompilation.

 dependencies {
         implementation fileTree(dir: 'libs', include: ['*.jar'])
 
         implementation 'com.android.support:appcompat-v7:25.4.0'
         implementation 'com.android.support.constraint:constraint-layout:1.0.2'
         // …
 
         testImplementation 'junit:junit:4.12'
         androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
             exclude group: 'com.android.support', module: 'support-annotations'
         })
 }

Explain More:

Before Android Gradle plugin 3.0: we had a big problem which is one code change causes all modules to be recompiled. The root cause for this is that Gradle doesn’t know if you leak the interface of a module through another one or not.

After Android Gradle plugin 3.0: the latest Android Gradle plugin now requires you to explicitly define if you leak a module’s interface. Based on that it can make the right choice on what it should recompile.

As such the compile dependency has been deprecated and replaced by two new ones:

  • api: you leak the interface of this module through your own interface, meaning exactly the same as the old compile dependency

  • implementation: you only use this module internally and does not leak it through your interface

So now you can explicitly tell Gradle to recompile a module if the interface of a used module changes or not.

Courtesy of Jeroen Mols blog


Gradle 3.0 introduced next changes:

  • compile -> api

    api keyword is the same as deprecated compile which expose this dependency for all levels

  • compile -> implementation

    Is preferable way because has some advantages. implementation expose dependency only for one level up at build time (the dependency is available at runtime). As a result you have a faster build(no need to recompile consumers which are higher then 1 level up)

  • provided -> compileOnly

    This dependency is available only in compile time(the dependency is not available at runtime). This dependency can not be transitive and be .aar. It can be used with compile time annotation processor and allows you to reduce a final output file

  • compile -> annotationProcessor

    Very similar to compileOnly but also guarantees that transitive dependency are not visible for consumer

  • apk -> runtimeOnly

    Dependency is not available in compile time but available at runtime.

[POM dependency type]


Since version 5.6.3 Gradle documentation provides simple rules of thumb to identify whether an old compile dependency (or a new one) should be replaced with an implementation or an api dependency:

  • Prefer the implementation configuration over api when possible

This keeps the dependencies off of the consumer’s compilation classpath. In addition, the consumers will immediately fail to compile if any implementation types accidentally leak into the public API.

So when should you use the api configuration? An API dependency is one that contains at least one type that is exposed in the library binary interface, often referred to as its ABI (Application Binary Interface). This includes, but is not limited to:

  • types used in super classes or interfaces
  • types used in public method parameters, including generic parameter types (where public is something that is visible to compilers. I.e. , public, protected and package private members in the Java world)
  • types used in public fields
  • public annotation types

By contrast, any type that is used in the following list is irrelevant to the ABI, and therefore should be declared as an implementation dependency:

  • types exclusively used in method bodies
  • types exclusively used in private members
  • types exclusively found in internal classes (future versions of Gradle will let you declare which packages belong to the public API)

The brief difference in layman's term is:

  • If you are working on an interface or module that provides support to other modules by exposing the members of the stated dependency you should be using 'api'.
  • If you are making an application or module that is going to implement or use the stated dependency internally, use 'implementation'.
  • 'compile' worked same as 'api', however, if you are only implementing or using any library, 'implementation' will work better and save you resources.

read the answer by @aldok for a comprehensive example.


This answer will demonstrate the difference between implementation, api, and compile on a project.


Let's say I have a project with three Gradle modules:

  • app (an Android application)
  • myandroidlibrary (an Android library)
  • myjavalibrary (a Java library)

app has myandroidlibrary as dependencies. myandroidlibrary has myjavalibrary as dependencies.

Dependency1

myjavalibrary has a MySecret class

public class MySecret {

    public static String getSecret() {
        return "Money";
    }
}

myandroidlibrary has MyAndroidComponent class that manipulate value from MySecret class.

public class MyAndroidComponent {

    private static String component = MySecret.getSecret();

    public static String getComponent() {
        return "My component: " + component;
    }    
}

Lastly, app is only interested in the value from myandroidlibrary

TextView tvHelloWorld = findViewById(R.id.tv_hello_world);
tvHelloWorld.setText(MyAndroidComponent.getComponent());

Now, let's talk about dependencies...

app need to consume :myandroidlibrary, so in app build.gradle use implementation.

(Note: You can use api/compile too. But hold that thought for a moment.)

dependencies {
    implementation project(':myandroidlibrary')      
}

Dependency2

What do you think myandroidlibrary build.gradle should look like? Which scope we should use?

We have three options:

dependencies {
    // Option #1
    implementation project(':myjavalibrary') 
    // Option #2
    compile project(':myjavalibrary')      
    // Option #3
    api project(':myjavalibrary')           
}

Dependency3

What's the difference between them and what should I be using?

Compile or Api (option #2 or #3) Dependency4

If you're using compile or api. Our Android Application now able to access myandroidcomponent dependency, which is a MySecret class.

TextView textView = findViewById(R.id.text_view);
textView.setText(MyAndroidComponent.getComponent());
// You can access MySecret
textView.setText(MySecret.getSecret());

Implementation (option #1)

Dependency5

If you're using implementation configuration, MySecret is not exposed.

TextView textView = findViewById(R.id.text_view);
textView.setText(MyAndroidComponent.getComponent());
// You can NOT access MySecret
textView.setText(MySecret.getSecret()); // Won't even compile

So, which configuration you should choose? That really depends on your requirement.

If you want to expose dependencies use api or compile.

If you don't want to expose dependencies (hiding your internal module) then use implementation.

Note:

This is just a gist of Gradle configurations, refer to Table 49.1. Java Library plugin - configurations used to declare dependencies for more detailed explanation.

The sample project for this answer is available on https://github.com/aldoKelvianto/ImplementationVsCompile


  • implementation: mostly we use implementation configuration. It hides the internal dependency of the module to its consumer to avoid accidental use of any transitive dependency, hence faster compilation and less recompilation.

  • api: must be used very carefully, since it leaks the to consumer’s compile classpath, hence misusing of api could lead to dependency pollution.

  • compileOnly: when we don’t need any dependency at runtime, since compileOnly dependency won’t become the part of the final build. we will get a smaller build size.

  • runtimeOnly: when we want to change or swap the behaviour of the library at runtime (in final build).

I have created a post with an in-depth understanding of each one with Working Example: source code

https://medium.com/@gauraw.negi/how-gradle-dependency-configurations-work-underhood-e934906752e5

Gradle configurations


Compile configuration was deprecated and should be replaced by implementation or api.

You can read the docs at https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_separation.

The brief part being-

The key difference between the standard Java plugin and the Java Library plugin is that the latter introduces the concept of an API exposed to consumers. A library is a Java component meant to be consumed by other components. It's a very common use case in multi-project builds, but also as soon as you have external dependencies.

The plugin exposes two configurations that can be used to declare dependencies: api and implementation. The api configuration should be used to declare dependencies which are exported by the library API, whereas the implementation configuration should be used to declare dependencies which are internal to the component.

For further explanation refer to this image. Brief explanation


+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| Name               | Role                 | Consumable? | Resolveable? | Description                             |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| api                | Declaring            |      no     |      no      | This is where you should declare        |
|                    | API                  |             |              | dependencies which are transitively     |
|                    | dependencies         |             |              | exported to consumers, for compile.     |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| implementation     | Declaring            |      no     |      no      | This is where you should                |
|                    | implementation       |             |              | declare dependencies which are          |
|                    | dependencies         |             |              | purely internal and not                 |
|                    |                      |             |              | meant to be exposed to consumers.       |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| compileOnly        | Declaring compile    |     yes     |      yes     | This is where you should                |
|                    | only                 |             |              | declare dependencies                    |
|                    | dependencies         |             |              | which are only required                 |
|                    |                      |             |              | at compile time, but should             |
|                    |                      |             |              | not leak into the runtime.              |
|                    |                      |             |              | This typically includes dependencies    |
|                    |                      |             |              | which are shaded when found at runtime. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| runtimeOnly        | Declaring            |      no     |      no      | This is where you should                |
|                    | runtime              |             |              | declare dependencies which              |
|                    | dependencies         |             |              | are only required at runtime,           |
|                    |                      |             |              | and not at compile time.                |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testImplementation | Test dependencies    |      no     |      no      | This is where you                       |
|                    |                      |             |              | should declare dependencies             |
|                    |                      |             |              | which are used to compile tests.        |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testCompileOnly    | Declaring test       |     yes     |      yes     | This is where you should                |
|                    | compile only         |             |              | declare dependencies                    |
|                    | dependencies         |             |              | which are only required                 |
|                    |                      |             |              | at test compile time,                   |
|                    |                      |             |              | but should not leak into the runtime.   |
|                    |                      |             |              | This typically includes dependencies    |
|                    |                      |             |              | which are shaded when found at runtime. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testRuntimeOnly    | Declaring test       |      no     |      no      | This is where you should                |
|                    | runtime dependencies |             |              | declare dependencies which              |
|                    |                      |             |              | are only required at test               |
|                    |                      |             |              | runtime, and not at test compile time.  |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+

Just by looking at the image from the help pages, it makes a lot of sense.

So you have the blue boxes compileClasspath and runtimeClassPath. The compileClasspath is what is required to make a successful build when running gradle build. The libraries that will be present on the classpath when compiling will be all libraries that are configured in your gradle build using either compileOnly or implementation.

Then we have the runtimeClasspath and those are all packages that you added using either implementation or runtimeOnly. All those libraries will be added to the final build file (jar) that you deploy on the server.

As you also see in the image, if you want a library to be both used for compilation but you also want it added to the build file, then implementation should be used.

An example of runtimeOnly can be a database driver.
An example of compileOnly can be servlet-api.
An example of implementation can be spring-core.

Gradle


Examples related to gradle

Gradle - Move a folder from ABC to XYZ A failure occurred while executing com.android.build.gradle.internal.tasks Gradle: Could not determine java version from '11.0.2' Android Gradle 5.0 Update:Cause: org.jetbrains.plugins.gradle.tooling.util Deprecated Gradle features were used in this build, making it incompatible with Gradle 5.0 Failed to resolve: com.android.support:appcompat-v7:28.0 Failed to resolve: com.google.firebase:firebase-core:16.0.1 com.google.android.gms:play-services-measurement-base is being requested by various other libraries java.lang.NoClassDefFoundError:failed resolution of :Lorg/apache/http/ProtocolVersion Error - Android resource linking failed (AAPT2 27.0.3 Daemon #0)

Examples related to build.gradle

Android Material and appcompat Manifest merger failed Unable to resolve dependency for ':app@debug/compileClasspath': Could not resolve Android dependency has different version for the compile and runtime Setting up Gradle for api 26 (Android) What's the difference between implementation and compile in Gradle? More than one file was found with OS independent path 'META-INF/LICENSE' Android Studio - Failed to notify project evaluation listener error Gradle error: Minimum supported Gradle version is 3.3. Current version is 3.2 All com.android.support libraries must use the exact same version specification DELETE_FAILED_INTERNAL_ERROR Error while Installing APK

Examples related to dependency-management

What's the difference between implementation and compile in Gradle? How to install a specific version of package using Composer? How to clear cache in Yarn? Javascript require() function giving ReferenceError: require is not defined How to add local .jar file dependency to build.gradle file? How to clean old dependencies from maven repositories? Android Studio: Add jar as library? Dealing with "Xerces hell" in Java/Maven? How do I add a Maven dependency in Eclipse? Force re-download of release dependency using Maven

Examples related to gradle-plugin

Android Material and appcompat Manifest merger failed What's the difference between implementation and compile in Gradle? Gradle's dependency cache may be corrupt (this sometimes occurs after a network connection timeout.)

Examples related to transitive-dependency

What's the difference between implementation and compile in Gradle?