The Claude API works seamlessly with Java and Spring Boot through Anthropic's official Java SDK or direct HTTP calls. To integrate Claude into a Spring Boot application: add the anthropic-java dependency, inject an Anthropic client bean, and call client.messages().create(...). Response latency averages 800ms–1.5s for typical 500-token prompts; streaming cuts perceived latency to under 200ms for the first token. This guide covers Maven/Gradle setup, synchronous and async patterns, Spring DI wiring, streaming responses, error handling, and production best practices.
Maven and Gradle Setup
Anthropic provides an official Java SDK published to Maven Central.
Maven (pom.xml):
<dependency>
<groupId>com.anthropic</groupId>
<artifactId>anthropic-java</artifactId>
<version>1.3.0</version>
</dependency>
Gradle (build.gradle):
implementation 'com.anthropic:anthropic-java:1.3.0'
Set your API key as an environment variable — never hardcode it:
export ANTHROPIC_API_KEY=sk-ant-...
Spring Boot Configuration
Create a configuration bean so the client is injected wherever needed:
@Configuration
public class AnthropicConfig {
@Value("${anthropic.api-key:#{environment.ANTHROPIC_API_KEY}}")
private String apiKey;
@Bean
public Anthropic anthropicClient() {
return Anthropic.builder()
.apiKey(apiKey)
.build();
}
}
Add to application.properties:
anthropic.model=claude-sonnet-4-5
anthropic.max-tokens=1024
Synchronous Message Call
The simplest usage: inject the client into a service and call messages().create().
@Service
@RequiredArgsConstructor
public class ClaudeService {
private final Anthropic client;
@Value("${anthropic.model}")
private String model;
public String ask(String userMessage) {
MessageCreateParams params = MessageCreateParams.builder()
.model(model)
.maxTokens(1024)
.addUserMessage(userMessage)
.build();
Message response = client.messages().create(params);
return response.content().get(0).text();
}
}
Benchmark: on a Mac mini M4, a 300-token prompt + 200-token completion averages 920ms round-trip.
Upgrade your Claude API skills: Claude API & Agent SDK Cookbook (P2, $49) — 30+ production-ready Java, Python, and TypeScript recipes with Spring Boot examples.
Async and CompletableFuture
For non-blocking Spring MVC or WebFlux controllers, wrap calls in CompletableFuture:
@Async
public CompletableFuture<String> askAsync(String userMessage) {
MessageCreateParams params = MessageCreateParams.builder()
.model(model)
.maxTokens(1024)
.addUserMessage(userMessage)
.build();
Message response = client.messages().create(params);
String text = response.content().get(0).text();
return CompletableFuture.completedFuture(text);
}
Enable async processing in your main class or config:
@EnableAsync
@SpringBootApplication
public class MyApp { ... }
Streaming Responses
Streaming is critical for chat UIs — users see the first word in under 200ms instead of waiting for the full response.
public void streamToConsumer(String userMessage, Consumer<String> onToken) {
MessageCreateParams params = MessageCreateParams.builder()
.model(model)
.maxTokens(1024)
.addUserMessage(userMessage)
.build();
client.messages().stream(params).subscribe(event -> {
if (event instanceof ContentBlockDeltaEvent delta) {
String chunk = delta.delta().text();
if (chunk != null) onToken.accept(chunk);
}
});
}
For a Spring MVC SSE endpoint:
@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter streamResponse(@RequestParam String prompt) {
SseEmitter emitter = new SseEmitter(30_000L);
executorService.submit(() -> {
claudeService.streamToConsumer(prompt, token -> {
try { emitter.send(token); }
catch (IOException e) { emitter.completeWithError(e); }
});
emitter.complete();
});
return emitter;
}
System Prompts and Multi-Turn Conversations
Add a system prompt to give Claude a persona or task context:
MessageCreateParams params = MessageCreateParams.builder()
.model(model)
.maxTokens(2048)
.system("You are a helpful Java code reviewer. Be concise and precise.")
.addUserMessage("Review this method: " + code)
.build();
For multi-turn conversations, accumulate the message history:
List<MessageParam> history = new ArrayList<>();
history.add(MessageParam.ofUser("What is dependency injection?"));
history.add(MessageParam.ofAssistant("Dependency injection is..."));
history.add(MessageParam.ofUser("Give a Spring Boot example."));
MessageCreateParams params = MessageCreateParams.builder()
.model(model)
.maxTokens(1024)
.messages(history)
.build();
Error Handling and Retry
Production apps must handle rate limits (429) and transient errors (529):
public String askWithRetry(String userMessage, int maxRetries) {
int attempt = 0;
while (attempt < maxRetries) {
try {
return ask(userMessage);
} catch (AnthropicRateLimitException e) {
long backoff = (long) Math.pow(2, attempt) * 1000;
Thread.sleep(backoff);
attempt++;
} catch (AnthropicApiException e) {
if (e.statusCode() >= 500) {
attempt++;
Thread.sleep(1000L * attempt);
} else {
throw e; // 4xx errors are not retryable
}
}
}
throw new RuntimeException("Max retries exceeded");
}
Key error types:
AnthropicRateLimitException— 429, back off exponentiallyAnthropicApiException— general API errors, checkstatusCode()AnthropicAuthenticationException— 401, invalid API key
Prompt Caching for Cost Reduction
If you repeat the same large system prompt across requests, enable prompt caching to reduce costs by up to 90% on cached tokens:
MessageCreateParams params = MessageCreateParams.builder()
.model(model)
.maxTokens(1024)
.system(List.of(
TextBlockParam.builder()
.text(longSystemPrompt) // must be >1024 tokens
.cacheControl(CacheControlEphemeral.builder().build())
.build()
))
.addUserMessage(userMessage)
.build();
See the Claude API cost and prompt caching break-even guide for a full ROI analysis.
Structured JSON Output
For data extraction, instruct Claude to return JSON and parse with Jackson:
String prompt = """
Extract the following fields from this support ticket as JSON:
{ "category": string, "priority": "high"|"medium"|"low", "summary": string }
Ticket: %s
""".formatted(ticketText);
String json = ask(prompt);
ObjectMapper mapper = new ObjectMapper();
TicketData data = mapper.readValue(json, TicketData.class);
For guaranteed structure, use the Claude structured outputs guide.
30+ production recipes: Claude API & Agent SDK Cookbook (P2, $49) — Spring Boot starters, retry utilities, streaming SSE, and cost optimization templates.
Frequently Asked Questions
Is there an official Anthropic Java SDK?
Yes. Anthropic publishes anthropic-java to Maven Central. Add the dependency to your pom.xml or build.gradle and use the Anthropic client class. As of April 2026 the latest stable version is 1.3.0.
How do I set the API key in a Spring Boot app?
Use an environment variable ANTHROPIC_API_KEY and read it via @Value("${anthropic.api-key:#{environment.ANTHROPIC_API_KEY}}") in your @Configuration class. Never hardcode keys in source code or application.properties committed to version control.
Does the Java SDK support streaming?
Yes. Call client.messages().stream(params) which returns a reactive stream. You can subscribe to ContentBlockDeltaEvent events to get token-by-token text chunks, suitable for SSE endpoints in Spring MVC or reactive handlers in WebFlux.
How do I use Claude in a Spring WebFlux reactive app?
Wrap the synchronous SDK calls in Mono.fromCallable(() -> ask(prompt)).subscribeOn(Schedulers.boundedElastic()). This offloads the blocking HTTP call to a thread pool without blocking the event loop.
What is the rate limit for the Claude API?
Default tier: 50 requests/minute, 40,000 tokens/minute for claude-sonnet-4-5. Limits scale with usage tier. Implement exponential backoff on AnthropicRateLimitException (HTTP 429). Enterprise tiers offer higher limits — contact Anthropic sales.
How does prompt caching work in Java?
Add a CacheControlEphemeral block to your system prompt parameter. The system prompt must exceed 1,024 tokens to be eligible. Cached tokens cost 10% of normal input token price, delivering up to 90% savings on repeated large prompts.
Can I use Claude for structured data extraction in Java?
Yes. Prompt Claude to return a JSON object matching your schema, then parse with Jackson (ObjectMapper). For strict schema enforcement, you can include the JSON Schema in the prompt or use Claude's tool use feature to define the expected output structure.
Related Guides
- Claude Agent SDK Guide — Build full agentic workflows with tool use
- Claude Code Complete Guide — CLI and development automation
- API Cost Monitoring Guide — Track and optimize API spend
- Prompt Caching Break-Even Analysis — When caching pays off