Setup & Starters
|
This content was generated with the assistance of AI and should be verified against the official documentation of each tool and framework before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
Written against Spring AI 2.0.1, Spring Boot 4.1.x and Java 21 (verified 2026-09-29). Spring AI 2.0.x supports Spring
Boot 4.0.x and 4.1.x, needs Java 17 or later, and is built on Spring Framework 7, Jackson 3 and JSpecify; the
examples here use Java 21 and Maven. This page adds the first capability of the running DocsAssistant service: a
project skeleton that starts, finds its models and can be tested. DocsAssistant is a Spring Boot service that answers
questions about the Irurueta documentation; it uses the same Ollama llama3.1:8b chat model, nomic-embed-text
embeddings and pgvector store as Integrating with Spring AI,
so the two sections describe one application. The next page, ChatModel &
ChatClient, adds its chat endpoint. For the map of the whole sub-section see the
Spring AI overview.
The three moving parts
Spring AI is wired in three layers, and knowing which layer a problem lives in saves a lot of time. A starter is a
dependency that brings a provider module and its auto-configuration. The auto-configuration reads spring.ai.*
properties and registers beans such as ChatModel, EmbeddingModel and a prototype-scoped ChatClient.Builder. Your
code then depends only on the portable interfaces, so changing provider is mostly a matter of changing a dependency and
a few properties.
spring-ai-starter-model-ollama"] --> M["Provider module
spring-ai-ollama"] S --> A["Auto-configuration
reads spring.ai.ollama.*"] A --> CM["ChatModel"] A --> EM["EmbeddingModel"] CM --> CB["ChatClient.Builder
prototype bean"] P["spring.ai.model.chat=ollama"] -. "selects the provider" .-> A CB --> YOU["Your services and controllers"] CM --> YOU EM --> YOU
The dotted arrow is the switch that decides which provider’s auto-configuration is active; the flattened properties section below explains it. Source: Spring AI: Getting Started (BOM, repositories, dependency management).
The BOM
The Spring AI Bill of Materials declares one consistent version for every Spring AI module. It is a BOM only: it has no
plugin declarations and no reference to Spring Boot, so you keep the Spring Boot parent (or the Spring Boot BOM) for the
Boot versions and import the Spring AI BOM beside it. Once it is imported, starters need no <version>.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.1.1</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>docsassistant</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>21</java.version>
<spring-ai.version>2.0.1</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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-ollama</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-pgvector</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-chat-memory-repository-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
This pom.xml was resolved with Maven against Maven Central on 2026-09-29. Gradle builds import the same BOM with a
platform dependency, implementation platform("org.springframework.ai:spring-ai-bom:2.0.1"), and then declare the
starters without versions. Release versions come from Maven Central and need no extra repository; only snapshots and
milestones need the Spring snapshot repositories, and the reference warns that a Maven mirror declared as * hides
them. The baseline used throughout this sub-section is the stable 2.0 line (2.0.1); a 2.1 milestone exists but is not
used here. Source: Spring AI: Getting Started (BOM, repositories, dependency management).
Two details differ from what older tutorials and the books show. The web starter is now
spring-boot-starter-webmvc on Boot 4 (Spring Initializr generates it for the "Spring Web" choice), and the
version property is normally named spring-ai.version, which is also what Initializr writes.
Starter naming
Since Spring AI 1.0.0.M7 every starter follows one of a few patterns. The books that target 0.8.x or 1.0.x
still use the earlier spring-ai-<provider>-spring-boot-starter form, which no longer exists, so a copied dependency
block from an older source is the first thing to check when a resolve fails.
| Pattern | Purpose | Examples |
|---|---|---|
|
A model provider: chat and, where the provider offers them, embeddings, images, audio and moderation |
|
|
A vector store behind the portable |
|
|
A Model Context Protocol client or server |
|
|
Persistent storage for conversational memory |
|
|
The tool-search advisor for large tool catalogues |
|
The list of names above is taken from the 2.0.1 BOM. Some modules are not starters: the advisor that answers questions
from a vector store is spring-ai-vector-store-advisor (the old name spring-ai-advisors-vector-store was
renamed in 2.0), and the development-time integrations are spring-ai-spring-boot-docker-compose and
spring-ai-spring-boot-testcontainers. The chat-memory starters and the vector-store advisor are covered where they
are used: Chat Memory Repositories and
RAG advisors.
Several starters were removed in 2.0. There is no spring-ai-starter-model-azure-openai any more: Azure OpenAI is
reached through the OpenAI module, which has microsoft-foundry, deployment-name and related properties. The
dedicated MiniMax module was removed in favour of the Anthropic module, and the spring-ai-openai-sdk and
spring-ai-oci-genai modules were removed too. The full list is on
Migrating from 1.x to 2.x.
Provider families
Spring AI groups providers into families by how they are reached. The table lists what the 2.0.1 BOM ships as a starter, and what is reached through another starter. Which capabilities a provider offers (tools, streaming, multimodal input, native JSON) is maintained in the reference’s Chat Models Comparison; check it before choosing a model, because it changes faster than this page.
| Family | How you get it | Notes |
|---|---|---|
Local runtime |
|
The DocsAssistant default. The Ollama module also has embeddings and pulls models on start-up when asked to. See Local Models for other local runtimes |
OpenAI and OpenAI-compatible |
|
Chat, embeddings, images, audio transcription, text-to-speech and moderation. Groq, NVIDIA, Perplexity and the Docker
Model Runner are reached through this starter by pointing |
Anthropic Claude |
|
Text, PDF and image input. Models named in this sub-section: |
|
Multimodal input including audio and video |
|
Mistral AI, DeepSeek |
|
Mistral supports image and audio input |
Cloud platforms |
|
Converse is the API to prefer for chat on Bedrock |
Specialised |
|
Not general chat providers |
The hosted model names used elsewhere in the AI section (claude-sonnet-5, claude-opus-5-5, claude-haiku-4-5,
claude-fable-5-1, gpt-6-sol) appear in this sub-section only in provider matrices and option examples; the running
DocsAssistant example stays on local Ollama so that it runs without an account.
Flattened properties and provider selection
Spring AI 2.0 flattened the property paths: the .options segment that older releases and books put between the
provider and the setting is gone. A chat model is configured with spring.ai.openai.chat.model, not
spring.ai.openai.chat.options.model. The old spelling still exists in the metadata as a deprecated alias, which is why
copied configuration from an older source often keeps working and then shows deprecation warnings.
The second rule is that a provider is chosen per capability with spring.ai.model.<capability>. The keys are
spring.ai.model.chat, spring.ai.model.embedding, spring.ai.model.image, spring.ai.model.moderation,
spring.ai.model.audio.transcription and spring.ai.model.audio.speech. Their values are the provider names, for
example ollama, openai, anthropic, mistral, google-genai, deepseek and bedrock-converse. When the property
is absent, every chat auto-configuration on the classpath is active (the condition is matchIfMissing = true), so two
starters give two ChatModel beans and an ambiguity error on ChatClient.Builder. Setting the property is how you say
which one wins.
spring:
application:
name: docsassistant
ai:
model:
chat: ollama
embedding: ollama
ollama:
base-url: http://localhost:11434
init:
pull-model-strategy: when_missing
chat:
model: llama3.1:8b
temperature: 0.2
embedding:
model: nomic-embed-text
retry:
max-attempts: 3
backoff:
initial-interval: 2s
multiplier: 2
max-interval: 30s
vectorstore:
pgvector:
index-type: HNSW
distance-type: COSINE_DISTANCE
dimensions: 768
initialize-schema: true
table-name: docs_vector_store
chat:
memory:
repository:
jdbc:
initialize-schema: always
Every spring.ai.* key above was checked against the configuration metadata inside the 2.0.1 starter jars.
pull-model-strategy accepts always, when_missing and never. The retry block configures the shared retry
policy (RetryTemplate), which only the RestClient-based provider modules such as Ollama use, and is developed on
Production & Deployment. The vectorstore.pgvector values match the
vector-rag page, and the chat.memory.repository.jdbc key is used from
Chat Memory. Source: Spring AI: Ollama Chat.
Switching DocsAssistant to a hosted model is a profile change, not a code change. The API key comes from an environment variable and is never written into the file.
spring:
ai:
model:
chat: openai
embedding: ollama
openai:
api-key: ${OPENAI_API_KEY}
chat:
model: gpt-6-sol
reasoning-effort: medium
Source: Spring AI: OpenAI Chat.
spring:
ai:
model:
chat: anthropic
anthropic:
api-key: ${ANTHROPIC_API_KEY}
chat:
model: claude-sonnet-5
max-tokens: 4096
Source: Spring AI: Anthropic Chat.
Both profiles were validated against the metadata in the same way. Keeping keys in environment variables, or in a secret store that Spring Boot can read, matters more than it looks: a key that is committed once stays in the history. See Security & Guardrails for the wider picture.
Development-time services
DocsAssistant needs a PostgreSQL with pgvector and an Ollama. Spring Boot can start both for you during development and tests, and Spring AI contributes the connection details that Boot cannot know about.
Docker Compose
With spring-boot-docker-compose on the classpath, Spring Boot starts the services in a compose.yaml when the
application starts and stops them when it stops. Spring AI’s spring-ai-spring-boot-docker-compose adds service
connections that match the container image name, among them ollama/ollama, so spring.ai.ollama.base-url is filled in
from the mapped port. PostgreSQL’s connection comes from Boot itself; a pgvector/pgvector image is not called
postgres, so a label tells Boot to treat it as one.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-docker-compose</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-spring-boot-docker-compose</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
Source: Spring AI: Docker Compose.
services:
ollama:
image: 'ollama/ollama:0.34.4'
ports:
- '11434'
pgvector:
image: 'pgvector/pgvector:pg17'
environment:
- 'POSTGRES_DB=docsassistant'
- 'POSTGRES_USER=docs'
- 'POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?set it in .env}'
labels:
- 'org.springframework.boot.service-connection=postgres'
ports:
- '5432'
The password comes from the environment or from a .env file next to compose.yaml (kept out of version control), and Compose
refuses to start without it; Spring Boot reads the resolved value from the running container, so nothing is duplicated in
application.yml. Real environments inject credentials from a secret store. Spring Initializr generates this same shape of file (with an ollama/ollama
image and a pgvector/pgvector image carrying the service-connection=postgres label) when the Docker Compose
dependency is selected. See Compose for Local Development for
Compose itself. Source: Spring AI: Docker Compose.
Testcontainers
Testcontainers is the alternative when the containers should live and die with the JVM, which is what tests and a
"run without Compose" development entry point want. A @ServiceConnection bean turns a running container into the
matching connection details; Spring AI’s spring-ai-spring-boot-testcontainers module recognises
OllamaContainer, and Spring Boot’s own spring-boot-testcontainers recognises PostgreSQL.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-spring-boot-testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-postgresql</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-ollama</artifactId>
<scope>test</scope>
</dependency>
Source: Spring AI: Testcontainers.
package com.example.docsassistant;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;
import org.testcontainers.postgresql.PostgreSQLContainer;
import org.testcontainers.ollama.OllamaContainer;
import org.testcontainers.utility.DockerImageName;
@TestConfiguration(proxyBeanMethods = false)
class DevServicesConfiguration {
@Bean
@ServiceConnection
PostgreSQLContainer pgvector() {
return new PostgreSQLContainer(
DockerImageName.parse("pgvector/pgvector:pg17").asCompatibleSubstituteFor("postgres"));
}
@Bean
@ServiceConnection
OllamaContainer ollama() {
return new OllamaContainer("ollama/ollama:0.34.4");
}
}
Source: Spring AI: Testcontainers.
The test-side launcher wraps DocsAssistantApplication, the @SpringBootApplication main class that Spring Initializr generates (see Spring Initializr):
package com.example.docsassistant;
import org.springframework.boot.SpringApplication;
public class TestDocsAssistantApplication {
public static void main(String[] args) {
SpringApplication.from(DocsAssistantApplication::main)
.with(DevServicesConfiguration.class)
.run(args);
}
}
Running TestDocsAssistantApplication starts the application with both containers and the connection details wired,
without a compose.yaml. The same DevServicesConfiguration can be imported into @SpringBootTest classes, which
is how Testing builds its integration tests. The class-level @Testcontainers style with
static @Container fields also works and is shown on the
vector-rag testing section. The Ollama
container starts empty: the models still have to be pulled, either with spring.ai.ollama.init.pull-model-strategy or
with execInContainer("ollama", "pull", …). For Testcontainers itself see
Spring Boot Integration Tests with
Testcontainers. Source: Spring AI: Testcontainers.
Spring Initializr
Spring Initializr has an AI group of dependencies that maps one to one to the starters above:
for example spring-ai-ollama, spring-ai-openai, spring-ai-anthropic, spring-ai-vectordb-pgvector,
spring-ai-chat-memory-repository-jdbc, spring-ai-mcp-client, spring-ai-mcp-server and
spring-ai-tool-search-advisor. Its metadata on 2026-09-29 defaulted to Spring Boot 4.1.1 and Java 17, and the generated
pom.xml set spring-ai.version to 2.0.1. The command line below produced the DocsAssistant skeleton, with a
compose.yaml and both Docker Compose dependencies added because docker-compose was requested.
curl https://start.spring.io/starter.zip \
-d type=maven-project -d language=java \
-d bootVersion=4.1.1 -d javaVersion=21 \
-d groupId=com.example -d artifactId=docsassistant \
-d packageName=com.example.docsassistant \
-d dependencies=web,spring-ai-ollama,spring-ai-vectordb-pgvector,spring-ai-chat-memory-repository-jdbc,docker-compose \
-o docsassistant.zip
Note that the generated project also pulled in spring-ai-vector-store-advisor for the pgvector choice. Initializr’s
generated application.properties is nearly empty; the YAML above is what you add. Source:
Spring AI: Getting Started.
Checking that it works
A start-up runner that asks the model one question is the smallest check that the starter, the property and the connection all agree. It is a profile so that it never runs in production.
package com.example.docsassistant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@Configuration
@Profile("smoke")
class SmokeRunner {
private static final Logger log = LoggerFactory.getLogger(SmokeRunner.class);
@Bean
ApplicationRunner smoke(ChatClient.Builder builder) {
ChatClient chatClient = builder.build();
return args -> log.info("Model says: {}",
chatClient.prompt().user("Reply with the single word: ready").call().content());
}
}
Start it with SPRING_PROFILES_ACTIVE=smoke. If it fails, the usual causes are, in order: two chat starters and no
spring.ai.model.chat; a model name that was never pulled; a base-url that does not match the container’s mapped
port; and a missing API key variable. This page’s Java classes and both dev-service configurations compile against
Spring AI 2.0.1; the container and model behaviour needs Docker and was not run when the page was written. Source:
Spring AI: Chat Client API.