What's the difference between implementation, api and compile in Gradle?
Asked Answered
G

12

1291

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?

Gastropod answered 12/6, 2017 at 7:13 Comment(0)
G
1530

tl;dr

Just replace:

  • compile with implementation (if you don't need transitivity) or api (if you need transitivity)
  • testCompile with testImplementation
  • debugCompile with debugImplementation
  • androidTestCompile with androidTestImplementation
  • compileOnly is still valid. It was added in 3.0 to replace provided and not compile. (provided introduced when Gradle didn't have a configuration name for that use-case and named it after Maven's provided scope.)

It is one of the breaking changes coming with Android Gradle plugin 3.0 that Google announced at IO17.

The compile configuration is now deprecated and should be replaced by implementation or api

From the Gradle documentation:

dependencies {
    api("commons-httpclient:commons-httpclient:3.1")
    implementation("org.apache.commons:commons-lang3:3.5")
}

Dependencies appearing in the api configurations will be transitively exposed to consumers of the library, and as such will appear on the compile classpath of consumers.

Dependencies found in the implementation configuration will, on the other hand, not be exposed to consumers, and therefore not leak into the consumers' compile classpath. This comes with several benefits:

  • dependencies do not leak into the compile classpath of consumers anymore, so you will never accidentally depend on a transitive dependency
  • faster compilation thanks to reduced classpath size
  • less recompilations when implementation dependencies change: consumers would not need to be recompiled
  • cleaner publishing: when used in conjunction with the new maven-publish plugin, Java libraries produce POM files that Distinguish exactly between what is required to compile against the library and what is required to use the library at runtime (in other words, don't mix what is needed to compile the library itself and what is needed to compile against the library).

The compile configuration still exists, but should not be used as it will not offer the guarantees that the api and implementation configurations provide.


Note: If you only use a library in your app module -the common case- you won't notice any difference.
you will only see the difference if you have a complex project with modules depending on each other, or you are creating a library.


What is transitive dependency?

"transitivity" refers to the ability of a dependency to include its own set of dependencies.

For example, if Project A depends on Project B, and Project B depends on Project C, then Project A transitively depends on Project C.

When you declare a dependency with implementation, the transitive dependencies are not exposed to other modules that depend on this module.

When you declare a dependency with api, the transitive dependencies are exposed, meaning that other modules that depend on this module will also have access to the transitive dependencies.

Gastropod answered 12/6, 2017 at 7:13 Comment(27)
Who are the "consumers"?Audile
the consumer is the module using the library. in the case of Android, it's the Android application. I think this is clear and I'm not sure if this is what you are asking for.Gastropod
That is what it sounded like to me, too. But if I am making a library, of course I want its API to be exposed to the app. Otherwise, how would the app developer use my library? That's why I don't get the meaning of implementation hiding the dependency. Does my question make sense?Audile
yes, it makes sense now, if your app depends on library x which itself depends on y,z. if you use implementation only x api will be exposed, but if you use api y,z also will be exposed.Gastropod
Also, replace provided with compileOnlyIndus
Can somebody please explain in simple language?Postscript
Note that if you're actually building a public library and publishing it to a maven repository, Google doesn't provide the tools to complete the job. You must use the android-maven-publish plugin to create the POMs correctly and translate from Gradle's api/implementation to Maven's runtime/compile scope syntax. Link: github.com/wupdigital/android-maven-publishHolleyholli
I have follow up question. This solves conflicts between dependency version if they were hidden by implementation, but I still need to include the dependencies in app? Even though library that uses them has them as implementation?Cornelison
@Gastropod what is the replacement for flavor compile. e.g. devCompile to?Estas
I don't understand what you mean by "flavor compile" if you mean you have flavor called "devCompile" then it's not related to this change and you don't have to do anything;Gastropod
I have a separate question for this but I was making a new app that automatically used implementation. It always worked find running in debug, but many users had the app crash on start up as if the libraries using implementation were not available. Has anyone else had this problem? I don't want to use implementation if it will crash my app for the end user. example implementation 'com.android.support.constraint:constraint-layout:1.0.2' crashes but compile does not.Dissimulate
probably it's unrelated to implementation. I never heard of any problem like this, you could ask a separate question to further investigate your problem.Gastropod
Thanks for the link to the Gradle documentation. I'd like to note another important statement from there: "As a guideline, you should prefer the implementation configuration first: leakage of implementation types to consumers would then directly lead to a compile error of consumers, which would be solved either by removing the type from the public API, or promoting the dependency as an API dependency instead." This is explained in more detail in another answer, but I guess it'd be better to incorporate this since your answer is currently the top voted one.Alternative
So when should we use api instead of implementation?Autogiro
DO NOT replace compile with implementation if you're using the maven-publish plugin to publish a library to a maven repo. If your gradle dependency is compile, the generated pom will have a transitive compile scope dependency. If your gradle dependency is implementation, the generated pom will have a non-transitive runtime scope dependency.Pandybat
Note that if the library you are using is a local one (a .aar file in your libs folder) it will not be transitive, despite you use api.Fornicate
What @PauloMerson wrote. This answer is just flat out wrong.Assiduous
@Behnam can you please explain what is wrong with the answer.Gastropod
@PauloMerson Problem? Gradle documentation: "The compile, testCompile, runtime and testRuntime configurations inherited from the Java plugin are still available but are deprecated. You should avoid using them, as they are only kept for backwards compatibility." docs.gradle.org/current/userguide/java_library_plugin.htmlHeteroplasty
@Behnam Is it wrong? See my comment above, Gradle doc I'm looking at says these things are deprecated.Heteroplasty
But since this link is for the Java library plugin - maybe it's only deprecated for those purposes? Doesn't seem 100% clear. docs.gradle.org/current/userguide/java_library_plugin.htmlHeteroplasty
@Heteroplasty The first line (what most people see first) was asking you to replace compile with implementation. Period. I edited the answer to say replace compile with implementation (if you don't need transitivity) or api (if you need transitivity). Hopefully it will prevent others from misguidedly Find&Replace lib compile dependencies with implementation to then undo everything.Pandybat
@PauloMerson Your comment sounded like "keep using compile", which is deprecated. That change looks good.Heteroplasty
NOTE: you need to add the java-library plugin otherwise the api will not workMablemabry
If my application A depend on my library B which in turn depend on external library C to compile and run. But yet, i want this external library to be runtime only for my application A. What configuration should i use?Sarawak
@Gastropod what is "transitivity" ("if you don't need transitivity")?Chronograph
"transitivity" refers to the ability of a dependency to include its own set of dependencies. For example, if Project A depends on Project B, and Project B depends on Project C, then Project A transitively depends on Project C. When you declare a dependency with implementation, the transitive dependencies are not exposed to other modules that depend on this module. When you declare a dependency with api, the transitive dependencies are exposed, meaning that other modules that depend on this module will also have access to the transitive dependencies.Gastropod
L
522

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

Lanneret answered 22/1, 2018 at 18:55 Comment(10)
I have add dependency to one jar file using implementation, if it is not expose access to it why I am still able to get and my code is working fine?Nathanaelnathanial
@smkrn110 implementation will expose your jar library, but not your jar dependencies libraries.Lanneret
so is there not any difference between compile and api?Weese
@WijaySharma the accepted answer states that compile does not guarantee the same things that api guarantees.Longs
Caught java.lang.NoClassDefFoundError: Failed resolution of: L<package>/MySecret , when add dependency myandroidlibrary as .jar on app.Katz
@young that is expected if you don't use remote dependency management. Please refer this answer groups.google.com/forum/#!msg/adt-dev/0ZAP8AVUZVw/W25OGYgwTngJ . I also have detailed answer on this SO post https://mcmap.net/q/46496/-android-studio-generate-aar-with-dependencyLanneret
I think this should be the accepted answer. Well explained!Triplex
" It's simple and intuitive" when I'm reading it it's not simple and intuitive for me. Please elaborate on why myandroidlibrary should be implementation.Cason
@MarianPaździoch thanks for your feedback, I have update the answer. To answer your question: It doesn't matter which dependency scope app will use for myandroidlibrary, you can use api/compile or implementation. Because in this sample, app does not need to expose its dependency. Unlike myandroidlibrary module that will expose its dependency to app.Lanneret
@StevenW.Klassen that is the most undeserved downvote I've ever heard of. If you think the order of information is not optimal, suggest an edit instead of complaining about itInspect
L
83

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

You can read the docs at the API and implementation separation section.

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

Livorno answered 12/6, 2017 at 7:37 Comment(0)
F
50

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

Figurehead answered 7/1, 2018 at 21:16 Comment(0)
I
45
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| 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.  |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
Isomer answered 9/4, 2019 at 12:55 Comment(3)
Doesn't answer question directlyCenterboard
There is also a developmentOnlyBoyle
@Centerboard is right. testImplementation produces an import error in the test class, whereas implementation doesn't. I found this SO thread in my attempt to understand why. This answer does not explain why.Entremets
G
33

Gradle dependency configuration

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[About] 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]

Grandpapa answered 13/4, 2020 at 10:31 Comment(1)
So in other words, api = public, implementation = internal and compileOnly = private - I need to create such aliases for these functions as they are super confusing.Pedalfer
E
13

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.

Edmon answered 23/5, 2018 at 3:12 Comment(1)
But the thing is that if a person deliberately came here looking for the answer to these questions, then he isn't a layman after all.Livorno
R
10

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)
Reinsure answered 10/12, 2019 at 10:14 Comment(0)
Q
7
  • 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

Quemoy answered 13/10, 2020 at 6:37 Comment(0)
C
6

Some notes before going ahead; compile is deprecated and the docs state you should use implementation because compile will be removed in Gradle version 7.0. If you run your Gradle build with --warning-mode all you will see the following message;

The compile configuration has been deprecated for dependency declaration. This will fail with an error in Gradle 7.0. Please use the implementation configuration instead.


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 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

Caryloncaryn answered 21/2, 2021 at 9:38 Comment(0)
G
1

Other answers explained the difference.

Just make sure that for Kotlin DSL (build.gradle.kts), the functions should have parentheses and their string arguments enclosed in double quotes instead of single quotes:

  • Groovy (build.gradle)
    implementation 'com.android.support:appcompat-v7:25.0.0'
    testImplementation 'junit:junit:4.12'
    
  • Kotlin (build.gradle.kts)
    implementation("com.android.support:appcompat-v7:25.0.0")
    testImplementation("junit:junit:4.12")
    
Glovsky answered 25/1, 2022 at 12:5 Comment(0)
J
0

When you declare a dependency in a gradle project the codebase + its dependencies (declared as api) can by used by the consumer gradle project.

Lets take an example

We have level 1, level 2, level 3 as gradle projects.

level 1 uses level 2. level 2 uses level 3.

level 1 <- level 2 <- level 3

using api and implementation, we can control if classes of level 3 should be exposed to level 1.

enter image description here

How does this make build faster:

Any changes in level 3. doesn't required re-compilation of level 1. Especially in development, saves time.

Jaundice answered 13/12, 2021 at 9:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.