Skip to content
JavaAgentic

Type at least two characters. Try “RAG”, “pgvector” or “tool calling”.

Modern Build Tools & Dependency Management

Maven and Gradle for Java AI projects: managing Spring AI and LangChain4j versions with BOMs, multi-module layout for projects with separate ingestion and serving, and dependency hygiene.

Beginner4 min readUpdated
On this page

Dependency management is where AI projects quietly go wrong. This ecosystem moves fast enough that a loosely-pinned version breaks a build you did not touch, and mismatched module versions produce runtime errors that look like bugs in your code. Getting the build right saves hours of confusion.

Key Takeaways

  • Use a BOM to pin every spring-ai-* (or langchain4j-*) artifact to a compatible set.
  • Pin exact versions. A floating range in a fast-moving library breaks builds unpredictably.
  • Reach for multi-module only when parts have different lifecycles — e.g. heavy ingestion vs lean serving.
  • Gradle version catalogs centralise versions across modules; Maven's dependencyManagement does the same job.

The BOM is the important part

A Bill of Materials declares compatible versions for a whole family of artifacts. You import it once and stop specifying versions on individual dependencies.

pom.xml (Maven)
<properties>
  <!-- Pin exactly. Not a range, not "latest". -->
  <spring-ai.version>1.0.0</spring-ai.version>
</properties>
 
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-bom</artifactId>
      <version>${spring-ai.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
 
<dependencies>
  <!-- No <version> here — the BOM supplies it. -->
  <dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-openai</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-vector-store-pgvector</artifactId>
  </dependency>
</dependencies>
build.gradle.kts (Gradle)
dependencies {
    implementation(platform("org.springframework.ai:spring-ai-bom:1.0.0"))
    implementation("org.springframework.ai:spring-ai-starter-model-openai")
    implementation("org.springframework.ai:spring-ai-starter-vector-store-pgvector")
}

Gradle version catalogs

For multi-module Gradle projects, a version catalog centralises versions in one file so every module agrees.

gradle/libs.versions.toml
[versions]
spring-ai = "1.0.0"
langchain4j = "1.0.0"
 
[libraries]
spring-ai-bom = { module = "org.springframework.ai:spring-ai-bom", version.ref = "spring-ai" }
spring-ai-openai = { module = "org.springframework.ai:spring-ai-starter-model-openai" }
langchain4j-core = { module = "dev.langchain4j:langchain4j", version.ref = "langchain4j" }
a module's build.gradle.kts
dependencies {
    implementation(platform(libs.spring.ai.bom))
    implementation(libs.spring.ai.openai)
}

Change a version in one place and every module updates. The equivalent in Maven is a parent POM's dependencyManagement.

Multi-module: when and how

Split a project into modules when parts have genuinely different dependency sets or lifecycles. A common AI split:

A typical split: shared domain, a heavy ingestion module, and a lean serving module.

Why this split earns its keep: the ingestion module pulls in Apache Tika, PDF parsers and other heavy dependencies that the serving module has no reason to ship. Keeping them apart means your web service's image stays small and its attack surface narrow, and you can run ingestion as a separate batch job.

parent pom.xml
<modules>
  <module>common</module>
  <module>ingestion</module>
  <module>serving</module>
</modules>

Dependency hygiene for AI projects

  • Audit regularly. mvn dependency:tree or gradle dependencies — AI libraries pull in large transitive trees (HTTP clients, JSON libraries, ONNX runtimes). Know what you are shipping.
  • Scan for vulnerabilities. The OWASP Dependency-Check plugin or gradle dependencyCheckAnalyze in CI. AI libraries are young and their transitive dependencies churn.
  • Exclude what you do not use. Some starters bundle multiple providers; exclude the ones you do not need to shrink the image.
  • Watch for duplicate HTTP clients. Spring AI and LangChain4j may each bring their own; aligning them avoids surprises.

A reproducible build is the goal

The single most valuable property of your build configuration is reproducibility: the same source produces the same artifact today and in six months. Exact versions, a BOM, and a committed lockfile (Gradle) or a fully-pinned POM get you there. In a field where the libraries change weekly, that stability is what lets you tell a real regression from a dependency drift.

Next

You have completed Phase 0. Your Java foundation is ready.

Frequently Asked Questions

Maven or Gradle for a Spring AI project?
Either works well; both consume the Spring AI BOM cleanly. Choose Maven for its predictability and the fact that most Spring documentation uses it, or Gradle for faster incremental builds and version catalogs on larger multi-module projects. This is a team-preference decision, not a capability one.
Why use a BOM for AI dependencies?
A Bill of Materials pins compatible versions of every module in a fast-moving library as a set, so you declare the Spring AI version once and every spring-ai-* artifact you add inherits a version known to work together. Given how quickly this ecosystem moves, mismatched module versions are a common and confusing source of runtime errors that a BOM prevents.
Should I split my AI project into modules?
Split when parts have genuinely different lifecycles or dependencies — for example an offline ingestion module that pulls in heavy document parsers, and a lean serving module that does not. Do not split prematurely; a single module is simpler until a real boundary appears, such as wanting to run ingestion as a separate job.

Related tutorials