Maven/Gradle default config

Maven and Gradle ship with sensible defaults for single-developer, sequential workflows.

L1 · ASSISTEDWhat this level takes
MUSTNot met, not at this level
  • A build system is in place (default configuration is fine)
  • Builds run on each change
SHOULDExpected in practice, not required
  • Build completes (even if slowly)
  • CI runs builds on a shared queue (even if everyone waits)
EVIDENCEHow you would check
  • Build configuration file with default/untuned settings
  • CI logs showing full rebuild on every PR

What It Is

Maven and Gradle ship with sensible defaults for single-developer, sequential workflows. A pom.xml or build.gradle that runs mvn package or gradle build compiles all source files, runs all tests, and produces all artifacts on every invocation. This is the configuration that comes out of project generators, IDE scaffolding, and most tutorial setups. For a team of humans committing a few times per day, it works well enough.

The problem emerges when AI agents enter the picture. An agent iterating on a bug fix will invoke the build system 10-30 times to verify its changes - every test-fix-retest cycle triggers a full build. Default Maven and Gradle configurations have no concept of what changed since the last invocation. Without the Gradle Build Cache explicitly enabled, Gradle recompiles everything. Without Maven's incremental compilation flags set, Maven recompiles the entire module graph on every mvn compile.

Default configs also assume a single build at a time. There are no tuning parameters for concurrent builds competing for the same local Maven repository (~/.m2), the same Gradle cache (~/.gradle), or the same output directories. Running three agents simultaneously in worktrees against a default Gradle project produces lock contention, cache corruption, and builds that are slower than a single sequential build.

The L1 state is not a failure of Maven or Gradle - both tools support advanced caching and parallelism when explicitly configured. L1 is the failure to configure them. Organizations at L1 have not yet felt the pain of AI agent iteration cycles grinding against a default build configuration, usually because agent usage is still low enough that the bottleneck hasn't surfaced.

Why It Matters

  • Agent iteration speed is directly gated by build speed - an agent doing 20 iterations at 3 minutes per build spends an hour waiting for the build system; at 30 seconds per build it spends 10 minutes
  • Default configs block the path to parallel agents - without shared caches and concurrent build support, running multiple agents simultaneously makes build times worse, not better
  • Invisible cost accumulates - teams don't notice L1 build pain until they start running agents at scale; by then the cost is baked into every agent workflow
  • Upgrade path is well-known - Gradle Build Cache, incremental compilation, and daemon warm-up are documented, tested features; L1 is a configuration gap, not a fundamental limitation
  • CI and local diverge - default configs often behave differently locally vs. in CI (different JVM settings, different daemon behavior), making agent output less predictable

Getting Started

  1. Enable the Gradle Build Cache - Add org.gradle.caching=true to gradle.properties. For local development this enables task output caching across builds. Measure before and after with ./gradlew build --profile to confirm cache hit rates.
  2. Enable the Gradle daemon - Add org.gradle.daemon=true to gradle.properties. The daemon keeps the JVM warm between builds, eliminating JVM startup overhead on every agent iteration.
  3. Enable parallel execution - Add org.gradle.parallel=true to gradle.properties. This allows Gradle to execute independent subprojects in parallel on multi-core machines.
  4. Set JVM memory appropriately - Add org.gradle.jvmargs=-Xmx4g -XX:+HeapDumpOnOutOfMemoryError to avoid GC pauses during compilation. Default JVM memory settings are too conservative for large projects.
  5. Enable Maven incremental compilation - If using Maven, add the maven-compiler-plugin with <useIncrementalCompilation>true</useIncrementalCompilation>. This skips recompilation of source files that haven't changed.
  6. Measure baseline - Before any optimization, record your current build time with a clean cache (./gradlew clean build) and a warm cache (./gradlew build immediately after). The gap between these is your current cache effectiveness. Aim for the warm build to be under 60 seconds for a typical module.
TIP

Run ./gradlew build --scan to get a Gradle Build Scan - a detailed breakdown of which tasks are slow, which are cache misses, and what's running sequentially that could run in parallel. This is the fastest way to identify where your build time is going.

Common Pitfalls

Assuming default is good enough because it worked before. A build that takes 4 minutes is fine when humans run it a few times per day. It's catastrophic when agents run it 20 times per hour. The threshold for "acceptable" build time drops by an order of magnitude when AI agents enter the workflow. Revisit build performance assumptions when you introduce agents.

Enabling caching without understanding cache invalidation. The Gradle Build Cache stores task outputs keyed by inputs. If your tasks have undeclared inputs (reading environment variables, system time, non-deterministic code generation), the cache will produce incorrect outputs or miss hits entirely. Audit task inputs before enabling caching at scale.

Running agents against the same local cache directory. Multiple agents using the same ~/.gradle cache concurrently without a remote cache backend will contend on cache writes. The solution is a shared remote cache (Gradle Enterprise, BuildBuddy, or even a local HTTP cache) that handles concurrent reads and writes correctly.

Not testing CI and local parity. Default configs often differ between local developer machines and CI runners (daemon disabled in CI, different JVM flags, different file system behavior). Agents running locally with a warm daemon and agents running in CI against a cold environment see very different build times. Explicitly align these configurations.

Treating build config as a one-time setup. Build performance degrades as codebases grow. A configuration that produced 45-second builds six months ago might produce 3-minute builds today as new modules and tests were added. Build performance needs periodic re-evaluation, especially as agent usage scales.

How Different Roles See It

BobHEAD OF ENGINEERING

Bob's teams have adopted Claude Code for individual developer use. Agents are running, PRs are getting created, but developers are complaining that agent loops feel slow - the agent runs, waits, adjusts, waits again. Bob hasn't connected this to build performance; he thinks it's a model latency issue.

What Bob should do: Bob should ask his DevEx lead (Sarah) to instrument agent iteration cycle time and identify how much of that time is build wait time. The answer is almost always "more than you think." Once the bottleneck is quantified, the fix is a one-day Gradle configuration project: enable caching, the daemon, and parallel execution. Bob should treat this as an infrastructure investment with a direct return on agent throughput. A 50% reduction in build time doubles the number of agent iterations in a given time window - that compounds across every agent, every developer, every day.

SarahPRODUCTIVITY LEAD

Sarah tracks developer experience metrics and has noticed that agent usage has plateaued. Developers use agents for greenfield tasks but switch back to manual coding for iterative work. When she asks why, the answer is consistent: "waiting for the build is frustrating enough that it breaks the flow."

What Sarah should do: Sarah should add build time to her DevEx dashboard - specifically, the 50th and 95th percentile build time on agent-driven branches. She should then set a target: sub-60-second warm builds for any module an agent is likely to touch. The path from L1 to that target is well-understood: Gradle daemon, caching, parallel execution. Sarah should run the configuration change as a sprint task for one engineer, measure the before/after impact on agent session length (agents that get fast feedback iterate more), and use the result to justify further investment in L3 build tooling.

VictorSTAFF ENGINEER - AI CHAMPION

Victor has set up Gradle caching locally and his builds are fast. But he's noticed that when he runs 3-4 parallel agents in worktrees, the build times are slower than when he runs a single agent - cache contention, lock files, and occasional corruption.

What Victor should do: Victor should set up a local remote cache backend using the Gradle Build Cache Docker image or a simple HTTP cache server. This gives all his parallel worktrees a shared, concurrency-safe cache without requiring a full Gradle Enterprise setup. He should also configure each worktree's gradle.properties to point at the shared cache. Once parallel agents are hitting a shared cache rather than competing for a local file-system cache, build times should drop to near-single-agent levels. Victor should document this setup as the standard for parallel agent development and push for a team-wide remote cache at L3.

Where does your team actually sit on this?

This guide describes one level of one area. Run the assessment to place your team across all 16 areas, see which gates you have passed, and get a report you can take to your stakeholders.

Start the assessment