Most Spring Boot applications are built to run forever — waiting for HTTP requests, consuming from a queue, or processing events. But plenty of real-world jobs don’t work that way. Database migrations, nightly reports, data imports: these run once, finish, and stop. Spring Cloud Task is built exactly for this pattern.

What Is Spring Cloud Task?

Spring Cloud Task gives you a lightweight way to build Spring Boot applications that execute a finite workload and shut down cleanly. Every time one of these applications runs, the framework records a task execution — capturing start time, end time, exit code, and any exception that occurred.

That execution history is what makes Spring Cloud Task useful beyond plain CommandLineRunner apps. You get auditability out of the box: you can query which tasks ran, when they ran, whether they succeeded, and replay failed runs with the same parameters.

Core concepts

Task definition — any Spring Boot application annotated with @EnableTask. The application performs its work and exits when main() returns.

Task execution — a single run of a task. Each execution gets a unique ID and is persisted to a relational database (H2 for local dev, Postgres or MySQL in production).

TaskExecutionListener — an interface you can implement to hook into execution lifecycle events (start, end, failure).

Integration with Spring Batch — Spring Cloud Task can launch and track Spring Batch jobs, linking batch job executions to their parent task execution.


Setting Up Spring Cloud Task

Step 1: Add dependencies

Create a new Spring Boot project at start.spring.io. Add spring-cloud-starter-task and an H2 database for local metadata storage.

<!-- Spring Cloud Task -->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-task</artifactId>
</dependency>

<!-- In-memory H2 for task execution metadata -->
<dependency>
  <groupId>com.h2database</groupId>
  <artifactId>h2</artifactId>
  <scope>runtime</scope>
</dependency>

You’ll also need the Spring Cloud BOM in your <dependencyManagement> block to align versions:

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>2022.0.3</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

Step 2: Create a task application

Add @EnableTask to your main class. That single annotation tells Spring Cloud Task to instrument this application and record its execution.

package com.example.demo;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.task.configuration.EnableTask;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@EnableTask
public class DemoApplication {

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

    @Bean
    public CommandLineRunner commandLineRunner() {
        return args -> System.out.println("Hello, Spring Cloud Task!");
    }
}

The CommandLineRunner bean contains your task logic. When the application starts, it runs the runner, prints the message, and exits — with the full execution record written to the database.

Step 3: Configure task metadata storage

Spring Cloud Task needs a datasource to persist execution records. For local development, H2 in-memory mode requires no additional setup beyond the dependency. Add this to application.properties:

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.h2.console.enabled=true

For production, swap in Postgres or MySQL and Spring Cloud Task will create its schema automatically on first run (or you can manage it yourself with Flyway).

Step 4: Run the task

mvn spring-boot:run

Check the H2 console at http://localhost:8080/h2-console after the application exits. You’ll see a TASK_EXECUTION table with your run recorded, including start time, end time, and exit code 0.

Full source: github.com/katyella/spring-examples/tree/main/cloud/task


Advanced Example: Running a Spring Batch Job as a Task

The most common real-world use of Spring Cloud Task is running Spring Batch jobs in a tracked, auditable way. The integration is straightforward: add Spring Batch to the project and launch your job from a CommandLineRunner.

Step 1: Add Spring Batch

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-task</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-batch</artifactId>
</dependency>

Step 2: Define and launch the batch job

package com.example.demo;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.task.configuration.EnableTask;
import org.springframework.context.annotation.Bean;
import org.springframework.transaction.PlatformTransactionManager;

@SpringBootApplication
@EnableTask
@EnableBatchProcessing
public class BatchTaskApplication {

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

    @Bean
    public Job job(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
        Step step = new StepBuilder("step1", jobRepository)
            .tasklet((contribution, chunkContext) -> {
                System.out.println("Processing batch step...");
                return RepeatStatus.FINISHED;
            }, transactionManager)
            .build();

        return new JobBuilder("myJob", jobRepository)
            .start(step)
            .build();
    }

    @Bean
    public CommandLineRunner runner(JobLauncher jobLauncher, Job job) {
        return args -> {
            JobParameters params = new JobParametersBuilder()
                .addLong("run.id", System.currentTimeMillis())
                .toJobParameters();
            jobLauncher.run(job, params);
        };
    }
}

When you run this application, Spring Cloud Task records the outer task execution, and Spring Batch records the inner job execution. The two are linked — you can trace a batch job failure back to the specific task run that triggered it.


Lifecycle Hooks with TaskExecutionListener

If you need to react to task start or end events — sending a notification, updating a status table, logging to an external system — implement TaskExecutionListener:

import org.springframework.cloud.task.listener.TaskExecutionListener;
import org.springframework.cloud.task.repository.TaskExecution;
import org.springframework.stereotype.Component;

@Component
public class MyTaskListener implements TaskExecutionListener {

    @Override
    public void onTaskStartup(TaskExecution taskExecution) {
        System.out.println("Task started: " + taskExecution.getTaskName());
    }

    @Override
    public void onTaskEnd(TaskExecution taskExecution) {
        System.out.println("Task finished with exit code: " + taskExecution.getExitCode());
    }

    @Override
    public void onTaskFailed(TaskExecution taskExecution, Throwable throwable) {
        System.err.println("Task failed: " + throwable.getMessage());
    }
}

Spring Cloud Task discovers and calls listener beans automatically — no registration needed.


When to Use Spring Cloud Task

Spring Cloud Task is a good fit when you need:

  • Execution history — knowing which runs succeeded, failed, and when
  • Batch/task coordination — launching Batch jobs and linking their results to a parent task
  • Scheduled jobs — combined with Spring Cloud Data Flow or a cron trigger, you can schedule tasks and track each invocation
  • Idempotent reruns — execution IDs let you safely rerun failed tasks without double-processing

It’s probably overkill if you’re just wrapping a simple script that runs once and you don’t need auditability. But for anything production-grade that runs on a schedule or gets triggered by events, the execution history is worth the minimal setup cost.