DEV Community

Query Filter
Query Filter

Posted on

gradle-51

To clean up your build configuration and strip out heavy "fat" dependencies while keeping only what your codebase actually imports, you can use a combination of **Gradle's built-in dependency analysis tools** and the **`gradle-dependency-analysis-plugin`**.

Here is a step-by-step approach to audit, isolate, and cull unnecessary dependencies in **Gradle 7.5**.

---

## Step 1: Run the Built-In Dependency Insight

Before removing anything, run Gradle’s dependency insight report to identify **why** a heavy transitive library is being pulled into your build graph and **which top-level dependency** introduced it.

In your terminal, run:

Enter fullscreen mode Exit fullscreen mode


bash
./gradlew dependencyInsight --dependency --configuration compileClasspath


This generates a dependency tree showing the exact path from your `build.gradle` declaration down to the nested artifact.

---

## Step 2: Use the Dependency Analysis Plugin (Automated Audit)

The most accurate way to find unused direct dependencies (and indirect dependencies you *should* declare explicitly) is Autonomous Apps' **`dependency-analysis-gradle-plugin`**. It scans your bytecode against your declared dependency graph.

Add it to your root `build.gradle`:

Enter fullscreen mode Exit fullscreen mode


groovy
plugins {
id 'com.autonomousapps.dependency-analysis' version '1.19.0' // Fully compatible with Gradle 7.5
}


Then run the audit task:

Enter fullscreen mode Exit fullscreen mode


bash
./gradlew buildHealth


### What the report tells you:

1. **Unused dependencies:** Libraries declared in `dependencies { ... }` that your source code never references. You can delete these immediately.
2. **Transitively used dependencies:** Libraries drawn in by a "big" parent library that your code *does* reference directly.
3. **Undeclared dependencies:** Dependencies you rely on in code but only have access to because another library drew them in.

---

## Step 3: Cull the Big Library & Promote the Transitive Artifact

Once you identify that you only use a small sub-module or underlying transitive dependency from a heavy framework:

### Option A: Replace the Parent Library with the Specific Module

Many large frameworks (like AWS SDK, Jackson, Spring, or Google Guava/GCP) split their functionality into smaller artifacts. Instead of pulling in the top-level bundle, replace it with only the required sub-module.

Enter fullscreen mode Exit fullscreen mode


groovy
dependencies {
// ❌ Heavy bundle
// implementation 'com.amazonaws:aws-java-sdk:1.12.xxx'

// ✅ Specific modular artifact
implementation 'com.amazonaws:aws-java-sdk-s3:1.12.xxx'
Enter fullscreen mode Exit fullscreen mode

}


### Option B: Exclude the Heavy Parent and Declare the Sub-Dependency

If a library pulls in heavy transitive dependencies you *don't* want (like logging frameworks, UI tools, or large utility suites), explicitly exclude them:

Enter fullscreen mode Exit fullscreen mode


groovy
dependencies {
implementation('com.example:some-library:2.1.0') {
// Exclude the heavy transitive artifact
exclude group: 'org.heavy.framework', module: 'heavy-core'
}

// Explicitly declare ONLY the lightweight sub-dependency your code actually uses
implementation 'org.heavy.framework:lightweight-utils:1.0.0'
Enter fullscreen mode Exit fullscreen mode

}


---

## Step 4: Use Gradle Constraints for Version Control

When you strip out a top-level library and explicitly declare its underlying transitive library, use `constraints` to manage the version cleanly without locking yourself into rigid hardcodes:

Enter fullscreen mode Exit fullscreen mode


groovy
dependencies {
constraints {
implementation('net.bytebuddy:byte-buddy:1.14.12') {
because 'Explicitly managed version after removing parent library'
}
}

// Direct lightweight declaration
implementation 'net.bytebuddy:byte-buddy'
Enter fullscreen mode Exit fullscreen mode

}


---

## Summary Checklist

1. Run `./gradlew buildHealth` to get a list of **Unused** and **Transitively Used** dependencies.
2. Delete all **Unused** lines from `dependencies { }`.
3. For **Transitively Used** dependencies, add the specific lower-level artifact directly to `dependencies { }` and remove the top-level parent library.
4. Run `./gradlew test` to ensure your runtime classpath remains intact.
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
topstar_ai profile image
Luis Cruz

I found the step-by-step approach to auditing and culling unnecessary dependencies in Gradle 7.5 to be really helpful, especially the use of the gradle-dependency-analysis-plugin to scan bytecode against the declared dependency graph. The example of replacing the parent library with a specific modular artifact, such as swapping aws-java-sdk for aws-java-sdk-s3, is a great illustration of how to reduce dependency bloat. Have you considered using Gradle's dependencyInsight report in conjunction with the plugin to identify potential issues before running the buildHealth task, or are there any specific scenarios where one approach is more suitable than the other?