Spring Boot Reactive Elasticsearch Example

Elasticsearch is a document-based search engine that is fast and widely used. We can use the Spring boot reactive data libraries to interact with the Elasticsearch server while developing a reactive spring application.

In this article, we will learn how to interact with the Elasticsearch server from a reactive spring boot application.

Version details:

  • Spring boot: 2.7.3
  • Elasticsearch: 7.17.4
  • Java: 17

Table of Contents

We will create a simple Spring boot reactive Elasticsearch application that performs CRUD operations.

Adding the required dependencies

Spring boot framework provides starter dependency spring-boot-starter-data-elasticsearch that we can leverage to interact with the Elasticsearch server.

Since we are creating a reactive style application, we will use the spring-boot-starter-webflux starter dependency.


Adding Elasticsearch configuration

Next step is to create a configuration class, that extends AbstractReactiveElasticsearchConfiguration class’s reactiveElasticsearchClient() method. Here, we can specify the Elasticsearch connection string and other properties.

This ReactiveElasticsearchClient instance is used by the spring data repositories while performing the CRUD operations.

public class ReactiveRestClientConfig extends AbstractReactiveElasticsearchConfiguration {
    public ReactiveElasticsearchClient reactiveElasticsearchClient() {
        final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
        return ReactiveRestClients.create(clientConfiguration);

Creating Elasticsearch documents

We will create a document class that stores student details like name, address, subjects, etc.

First, we will create a Student class with details like enrolled subjects and address details, etc.

@Document(indexName = "student-details")
public class Student {
    private String id;
    @Field(type = FieldType.Text)
    private String firstName;
    private String lastName;
    private int age;
    @Field(type = FieldType.Date, format = DateFormat.date)
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
    private LocalDate joinDate;
    private Address address;
    private List<Subject> subjects;
  • We can specify the Elasticsearch document by annotating the class with the @Document annotation. We can also mention the index name of the Elasticsearch document.
  • Every Elasticsearch document needs a unique id field that is specified by annotating it with the @Id annotation.
  • Elasticsearch supports many document field types, and we can explicitly specify the field type with the help of @Field annotation.

Let’s also create an Address class that holds the student’s address details.

public class Address {
    private String street;
    private Integer doorNo;

Also, create a Subject class as shown below.

public class Subject {
    private String name;

Add the below configuration property into the spring boot application’s application.yml file.

By adding this, Jackson library generates Snake case JSON fields while converting the java classes to JSON.

    property-naming-strategy: SNAKE_CASE

Adding spring data repository

Create a StudentRepository interface that extends the ReactiveElasticsearchRepository interface. We can use this repository instance to perform CRUD operations on Elasticsearch documents.

We can also add custom finder methods, as shown below.

public interface StudentRepository extends ReactiveElasticsearchRepository<Student, String> {
    Flux<Student> findByFirstName(String firstName);

Adding CRUD implementation

Now let’s create a service layer to add CRUD functionality.

Create a StudentService interface and add the below method signatures.

public interface StudentService {
    Mono<Student> createStudent(Student student);
    Mono<Student> updateStudent(String id, Student student);
    Mono<String> deleteStudent(String id);
    Flux<Student> getStudentByFirstName(String firstName);
    Flux<Student> getAllStudents();

Create an implementation class and implement the methods defined in the service interface.

We use the Elasticsearch repository to interact with the server and CRUD operations.

public class StudentServiceImpl implements StudentService {

    private final StudentRepository studentRepository;

    public Mono<Student> createStudent(Student student) {
        return studentRepository.save(student);

    public Mono<Student> updateStudent(String id, Student student) {
        return studentRepository.findById(id).flatMap(std -> {
                    log.info("std-{}", std);
                    return studentRepository.save(std);
                .doOnError(e -> log.error(String.valueOf(e)));

    public Mono<String> deleteStudent(String id) {
        return studentRepository.deleteById(id)
                .thenReturn("Student deleted successfully!");

    public Flux<Student> getStudentByFirstName(String firstName) {
        return studentRepository.findByFirstName(firstName);

    public Flux<Student> getAllStudents() {
        return studentRepository.findAll();

Adding CRUD APIs

Finally, create the REST endpoints to expose the CRUD APIs, as shown below.

public class StudentController {

    private final StudentService studentService;

    public Mono<Student> createStudent(@RequestBody Student student){
        return studentService.createStudent(student);

    public Mono<Student> updateStudent(@RequestBody Student student, @PathVariable("id") String id) {
        return studentService.updateStudent(id, student);

    public Mono<String> deleteStudent(@PathVariable("id")  String id){
        return studentService.deleteStudent(id);

    public Flux<Student> getStudentByFirstname(@PathVariable("first-name") String firstName) {
        return studentService.getStudentByFirstName(firstName);

    public Flux<Student> getAllStudents() {
        return studentService.getAllStudents();

Testing the CRUD APIs

We will use the Postman tool to test our CRUD endpoints.

Run the application. By default, the application starts with port number 8080.

Create API

Invoke the POST API /students with the required student request JSON payload, as shown below.

spring boot elasticsearch example

Update API

To update the saved student document, we can use the PUT API: /students/{id}.

Here, the id is the unique student id generated during the document creation.

spring boot elasticsearch example


We can fetch all the saved student documents by invoking the GET API: /students.

spring boot elasticsearch example

Delete API

To delete a particular student document, we can use the DELETE API: /students/{id}

Here, the id is the student document’s id.

spring boot elasticsearch example


In this post, we learned how easy it is to create a Spring boot reactive application and perform CRUD operations with Elasticsearch documents.

We also learned how the spring boot framework provides the necessary support for interacting with Elasticsearch by providing the Elasticsearch spring data starter library.

Example code is available on Git hub.