How to add local .jar file dependency to build.gradle file?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
To add a local .jar file as a dependency in Gradle, use implementation files('libs/example.jar') in your dependencies block. For multiple jars in a directory, use implementation fileTree(dir: 'libs', include: ['*.jar']). These are the two most common approaches, and each has trade-offs around scalability, version tracking, and build reproducibility that are worth understanding before choosing one.
Why You Might Need Local Jars
Most Java dependencies come from Maven Central or other remote repositories, but there are legitimate cases where a local jar is necessary:
- Proprietary libraries that are not published to any repository
- Modified forks of open-source libraries with custom patches
- Legacy projects where migrating to a repository manager is not yet feasible
- Offline builds in air-gapped environments without internet access
- Vendor SDKs distributed as downloadable jar files
Project Structure Convention
Place local jars in a libs directory at the root of your project or module. This is a widely recognized convention that other developers will understand immediately.
For multi-module projects, each module can have its own libs directory, or you can share one at the root level.
Method 1: Direct File Reference
The simplest approach references specific jar files directly.
In Kotlin DSL (build.gradle.kts):
This is explicit and predictable. You know exactly which jars are included. The downside is that adding a new jar requires editing the build file.
Method 2: File Tree (Directory Scan)
To include all jars in a directory without listing each one individually:
In Kotlin DSL:
This scales better when you have many jars, but it sacrifices visibility. A new jar dropped into the libs directory is automatically included without any explicit declaration, which can introduce surprises.
You can also filter by pattern:
Method 3: Flat Directory Repository
Gradle supports declaring a local directory as a flat repository. This approach allows you to reference jars by name without the .jar extension.
The flatDir repository tells Gradle to look in libs/ for artifacts. Gradle infers the .jar extension automatically.
This method integrates more naturally with Gradle's dependency resolution, but it has a significant limitation: flat directory repositories do not support transitive dependencies or metadata (POM files). Gradle cannot resolve the jar's own dependencies.
Method 4: Local Maven Repository (Recommended for Teams)
For teams that need reproducible builds and proper version management, publishing the jar to a local Maven repository is the cleanest solution.
Install the jar into the local Maven cache
Reference it in build.gradle
This gives you proper versioning, works with Gradle's dependency resolution, and integrates with existing repository infrastructure. The jar is stored in ~/.m2/repository/ like any other Maven artifact.
Comparison of Methods
| Method | Versioning | Transitive Deps | Team Friendly | Setup Effort |
files() | Manual | No | Low | Minimal |
fileTree() | Manual | No | Low | Minimal |
flatDir | Manual | No | Medium | Low |
mavenLocal() | Proper | Yes (with POM) | High | Moderate |
| Private repository (Nexus/Artifactory) | Proper | Yes | High | High |
Multi-Module Projects
In multi-module Gradle projects, the path in files() or fileTree() is relative to the module's directory, not the root project.
To reference jars from the root project's libs directory:
For sharing a common set of jars across modules, define them in the root build.gradle using subprojects or allprojects:
Android Projects
Android projects follow the same patterns, but Android Gradle Plugin versions before 3.0 used compile instead of implementation. Modern Android projects should use implementation or api.
Android Studio generates this fileTree declaration by default in new projects, which is why many Android developers encounter local jar dependencies early.
Common Pitfalls
- Forgetting to commit the jar to version control. If the jar is in
.gitignoreor simply not committed, the build breaks for other team members. Either commit the jars or use a shared repository. - Version conflicts with remote dependencies. A local jar may bundle classes that overlap with a remote dependency, causing
ClassNotFoundExceptionorNoSuchMethodErrorat runtime. Use./gradlew dependenciesto inspect the full dependency tree. - Using
compileinstead ofimplementation. Thecompileconfiguration is deprecated since Gradle 3.0. Useimplementation(private to the module) orapi(exposed to consumers). - Relative path confusion in multi-module builds.
files('libs/foo.jar')resolves relative to the current module, not the root project. Use${rootProject.projectDir}for root-relative paths. - No transitive dependency resolution. Local jars do not carry POM metadata. If the jar depends on other libraries, you must declare those dependencies manually or use
mavenLocal()with a proper POM. - Stale jars after updates. Replacing a jar in the
libsdirectory does not always trigger a rebuild. Run./gradlew cleanafter replacing a local jar to ensure the build picks up the new version.
Summary
- Use
files('libs/example.jar')for a small number of explicitly named jars. - Use
fileTree(dir: 'libs', include: ['*.jar'])to include all jars in a directory automatically. - Use
flatDirwhen you want repository-style name-based references without the jar extension. - For team environments, publish jars to
mavenLocal()or a private repository (Nexus, Artifactory) for proper versioning and transitive dependency support. - In multi-module projects, paths in
files()are relative to the module directory. Use${rootProject.projectDir}to reference jars from the root. - Always verify the dependency tree with
./gradlew dependenciesto catch version conflicts between local and remote jars.

