Skip to main content
The Java/Kotlin SDK provides an integration module with Spring Boot: your Restate services become Spring beans, so you can use dependency injection, configuration properties, and the rest of the Spring ecosystem.
Get started from a template with the Java (Maven + Spring Boot) or Kotlin (Gradle + Spring Boot) Quickstart.

Dependencies

Use the Spring Boot starter instead of the plain HTTP SDK dependency. It pulls in the SDK and auto-configures the Restate endpoint and client.
<properties>
    <restate.version>2.9.0</restate.version>
</properties>
<dependencies>
    <dependency>
        <groupId>dev.restate</groupId>
        <artifactId>sdk-spring-boot-starter</artifactId>
        <version>${restate.version}</version>
    </dependency>
</dependencies>

Enabling Restate

Add @EnableRestate to your Spring Boot application:
package com.example.restatestarter;

import dev.restate.sdk.springboot.EnableRestate;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableRestate
public class RestateStarterApplication {

	public static void main(String[] args) {
		SpringApplication.run(RestateStarterApplication.class, args);
	}

}

Defining services

Annotate your service class with @RestateComponent in addition to the usual @Service, @VirtualObject, or @Workflow annotation. Unlike the standalone setup, the service has no main: Spring Boot binds and serves it. @RestateComponent is like any other Spring’s @Component: inject configuration and other beans as usual (@Value, constructor injection, …).
@RestateComponent
@Service
public class Greeter {

  @Value("${greetingPrefix}")
  private String greetingPrefix;

  public record Greeting(String name) {}
  public record GreetingResponse(String message) {}

  @Handler
  public GreetingResponse greet(Greeting req) {
    // Durably execute a set of steps; resilient against failures
    String greetingId = Restate.random().nextUUID().toString();
    Restate.run("Notification", () -> sendNotification(greetingId, req.name));
    Restate.sleep(Duration.ofSeconds(1));
    Restate.run("Reminder", () -> sendReminder(greetingId, req.name));

    // Respond to caller
    return new GreetingResponse("You said " + greetingPrefix + " to " + req.name + "!");
  }
}
Everything inside the handler works exactly as in the standalone SDK: use the Restate static methods (Java) or the top-level functions in dev.restate.sdk.kotlin (Kotlin) for state, calls, side effects, and timers.

Calling Restate from Spring

The starter registers a Client bean. Inject it into any Spring component (controllers, scheduled tasks, …) to invoke your handlers from outside a Restate context:
package com.example.restatestarter;

import com.example.restatestarter.Greeter.Greeting;
import dev.restate.client.Client;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

	private final Client restateClient;

    public HelloController(Client restateClient) {
        this.restateClient = restateClient;
    }

    @GetMapping("/")
	public String index() {
		return restateClient.service(Greeter.class).greet(new Greeting("Alice")) + " from Spring Boot!";
	}

}
In Kotlin, inject the same Client bean through the constructor.

Configuration

Configure the SDK endpoint and the injected client via application.properties (or application.yml):
# Port where the Restate SDK endpoint is exposed (default 9080)
restate.sdk.http.port=9080

# Base URI of the Restate ingress, used by the injected Client
restate.client.base-uri=http://localhost:8080
Service- and handler-level options (retention, timeouts, retry policies, …) are set with restate.components.<ServiceName>.* properties. See service configuration for the full list.