Spring Boot is a popular framework that simplifies Java application development, especially for web applications. Quartz Scheduler is one of the most robust and flexible solutions for scheduling tasks. Quartz allows job scheduling with complex time-based execution patterns.
In this article, we’ll explore how to integrate Quartz Scheduler with Spring Boot, both with and without a database. We’ll cover the basics of Quartz, its configuration, and implementation for different use cases.
What is a Quartz Scheduler?
Quartz is a job scheduling library that allows scheduling and executing tasks at specific intervals or times. It supports:
- Cron-based scheduling (like UNIX cron jobs)
- Simple intervals (e.g., every 5 seconds)
- Persistent job storage (in a database)
- Clustering (for distributed execution)
Setting Up Quartz Scheduler in Spring Boot
To use Quartz in a Spring Boot project, you need to include the following dependency in your pom.xml
(for Maven):
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>
1. Quartz Scheduler Without Database
This approach stores job details in memory rather than in a database. It’s useful for lightweight applications where persistence isn’t necessary.
Step 1: Define a Quartz Job
A Quartz Job is a class that implements the Job
interface and define the task.
import lombok.extern.slf4j.Slf4j; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.stereotype.Component; @Component @Slf4j public class SimpleQuartzJob implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { log.info("Executing Quartz Job - {}", System.currentTimeMillis()); } }
Step 2: Configure Quartz Scheduler
Since we’re using an in-memory job store, we’ll define the scheduler configuration in application.properties
:
spring.quartz.job-store-type=memory spring.quartz.scheduler.instanceName=SimpleScheduler spring.quartz.threadPool.threadCount=5
Alternative application.yml
spring: quartz: job-store-type: memory scheduler: instance-name: SimpleScheduler thread-pool: thread-count: 5
Next, we create a configuration class to schedule the job:
import org.quartz.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class QuartzConfig { @Bean public JobDetail jobDetail() { return JobBuilder.newJob(SimpleQuartzJob.class) .withIdentity("simpleJob") .storeDurably() .build(); } @Bean public Trigger trigger(JobDetail jobDetail) { return TriggerBuilder.newTrigger() .forJob(jobDetail) .withIdentity("simpleTrigger") .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(10) .repeatForever()) .build(); } }
Step 3: Running the Application
Run the Spring Boot application, and you’ll see logs indicating that the job is executing every 10 seconds:
Executing Quartz Job - 1742460110793 Executing Quartz Job - 1742460120792
2. Quartz Scheduler With Database
If you need to persist job details, storing jobs in a database is the way to go. This ensures jobs survive application restarts and supports clustering.
Setting Up PostgreSQL Database Server

Step 1: Configure Database for Quartz
First, add the required database driver to pom.xml
:
<dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency>
Modify application.properties
to configure a database-backed job store:
spring.jpa.hibernate.ddl-auto=none spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl spring.jpa.show-sql=true spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect spring.datasource.url=jdbc:postgresql://localhost:5432/quartzdb spring.datasource.username=admin spring.datasource.password=password spring.datasource.driver-class-name=org.postgresql.Driver spring.quartz.job-store-type=jdbc spring.quartz.scheduler.instance-name=DBScheduler spring.quartz.jdbc.initialize-schema=always spring.quartz.properties.org.quartz.scheduler.instanceName=QuartzScheduler spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_ spring.quartz.properties.org.quartz.jobStore.isClustered=true spring.quartz.properties.org.quartz.threadPool.threadCount=10 spring.quartz.properties.org.quartz.threadPool.threadPriority=5
Alternative application.yml
spring: jpa: hibernate: ddl-auto: none naming: implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl show-sql: true properties: hibernate: dialect: org.hibernate.dialect.PostgreSQLDialect datasource: url: jdbc:postgresql://localhost:5432/quartzdb username: admin password: password driver-class-name: org.postgresql.Driver quartz: job-store-type: jdbc scheduler: instance-name: DBScheduler jdbc: initialize-schema: always properties: org.quartz.scheduler.instanceName: QuartzScheduler org.quartz.scheduler.instanceId: AUTO org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.PostgreSQLDelegate org.quartz.jobStore.tablePrefix: QRTZ_ org.quartz.jobStore.isClustered: true org.quartz.threadPool.threadCount: 10 org.quartz.threadPool.threadPriority: 5
Quartz Configuration Reference
Step 2: Create Database Tables
Quartz Scheduler PostgreSQL Table Creation Script (tables_postgres.sql
)
-- -------------------------------------------- -- Table structure for table `QRTZ_CALENDARS` -- -------------------------------------------- CREATE TABLE QRTZ_CALENDARS ( SCHED_NAME VARCHAR(120) NOT NULL, CALENDAR_NAME VARCHAR(200) NOT NULL, CALENDAR BYTEA NOT NULL, PRIMARY KEY (SCHED_NAME, CALENDAR_NAME) ); -- -------------------------------------------- -- Table structure for table `QRTZ_CRON_TRIGGERS` -- -------------------------------------------- CREATE TABLE QRTZ_CRON_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR(200) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, CRON_EXPRESSION VARCHAR(200) NOT NULL, TIME_ZONE_ID VARCHAR(80), PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP), FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP) ); -- -------------------------------------------- -- Table structure for table `QRTZ_FIRED_TRIGGERS` -- -------------------------------------------- CREATE TABLE QRTZ_FIRED_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, ENTRY_ID VARCHAR(95) NOT NULL, TRIGGER_NAME VARCHAR(200) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, INSTANCE_NAME VARCHAR(200) NOT NULL, FIRED_TIME BIGINT NOT NULL, SCHED_TIME BIGINT NOT NULL, PRIORITY INTEGER NOT NULL, STATE VARCHAR(16) NOT NULL, JOB_NAME VARCHAR(200), JOB_GROUP VARCHAR(200), IS_NONCONCURRENT BOOLEAN, REQUESTS_RECOVERY BOOLEAN, PRIMARY KEY (SCHED_NAME, ENTRY_ID) ); -- -------------------------------------------- -- Table structure for table `QRTZ_JOB_DETAILS` -- -------------------------------------------- CREATE TABLE QRTZ_JOB_DETAILS ( SCHED_NAME VARCHAR(120) NOT NULL, JOB_NAME VARCHAR(200) NOT NULL, JOB_GROUP VARCHAR(200) NOT NULL, DESCRIPTION VARCHAR(250), JOB_CLASS_NAME VARCHAR(250) NOT NULL, IS_DURABLE BOOLEAN NOT NULL, IS_NONCONCURRENT BOOLEAN NOT NULL, IS_UPDATE_DATA BOOLEAN NOT NULL, REQUESTS_RECOVERY BOOLEAN NOT NULL, JOB_DATA BYTEA, PRIMARY KEY (SCHED_NAME, JOB_NAME, JOB_GROUP) ); -- -------------------------------------------- -- Table structure for table `QRTZ_LOCKS` -- -------------------------------------------- CREATE TABLE QRTZ_LOCKS ( SCHED_NAME VARCHAR(120) NOT NULL, LOCK_NAME VARCHAR(40) NOT NULL, PRIMARY KEY (SCHED_NAME, LOCK_NAME) ); -- -------------------------------------------- -- Table structure for table `QRTZ_PAUSED_TRIGGER_GRPS` -- -------------------------------------------- CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, PRIMARY KEY (SCHED_NAME, TRIGGER_GROUP) ); -- -------------------------------------------- -- Table structure for table `QRTZ_SCHEDULER_STATE` -- -------------------------------------------- CREATE TABLE QRTZ_SCHEDULER_STATE ( SCHED_NAME VARCHAR(120) NOT NULL, INSTANCE_NAME VARCHAR(200) NOT NULL, LAST_CHECKIN_TIME BIGINT NOT NULL, CHECKIN_INTERVAL BIGINT NOT NULL, PRIMARY KEY (SCHED_NAME, INSTANCE_NAME) ); -- -------------------------------------------- -- Table structure for table `QRTZ_SIMPLE_TRIGGERS` -- -------------------------------------------- CREATE TABLE QRTZ_SIMPLE_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR(200) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, REPEAT_COUNT BIGINT NOT NULL, REPEAT_INTERVAL BIGINT NOT NULL, TIMES_TRIGGERED BIGINT NOT NULL, PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP), FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP) ); -- -------------------------------------------- -- Table structure for table `QRTZ_SIMPROP_TRIGGERS` -- -------------------------------------------- CREATE TABLE QRTZ_SIMPROP_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR(200) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, STR_PROP_1 VARCHAR(512), STR_PROP_2 VARCHAR(512), STR_PROP_3 VARCHAR(512), INT_PROP_1 INTEGER, INT_PROP_2 INTEGER, LONG_PROP_1 BIGINT, LONG_PROP_2 BIGINT, DEC_PROP_1 NUMERIC(13,4), DEC_PROP_2 NUMERIC(13,4), BOOL_PROP_1 BOOLEAN, BOOL_PROP_2 BOOLEAN, PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP), FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP) ); -- -------------------------------------------- -- Table structure for table `QRTZ_TRIGGERS` -- -------------------------------------------- CREATE TABLE QRTZ_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR(200) NOT NULL, TRIGGER_GROUP VARCHAR(200) NOT NULL, JOB_NAME VARCHAR(200) NOT NULL, JOB_GROUP VARCHAR(200) NOT NULL, DESCRIPTION VARCHAR(250), NEXT_FIRE_TIME BIGINT, PREV_FIRE_TIME BIGINT, PRIORITY INTEGER, TRIGGER_STATE VARCHAR(16) NOT NULL, TRIGGER_TYPE VARCHAR(8) NOT NULL, START_TIME BIGINT NOT NULL, END_TIME BIGINT, CALENDAR_NAME VARCHAR(200), MISFIRE_INSTR SMALLINT, JOB_DATA BYTEA, PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP), FOREIGN KEY (SCHED_NAME, JOB_NAME, JOB_GROUP) REFERENCES QRTZ_JOB_DETAILS (SCHED_NAME, JOB_NAME, JOB_GROUP) );
Explanation of Key Tables

View the Table using pgAdmin4
http://localhost:5050/browser/

Step 3: Modify the Configuration
Now, modify QuartzConfig
to use database storage:
import org.quartz.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class QuartzDBConfig { @Bean public JobDetail jobDetail() { return JobBuilder.newJob(DatabaseQuartzJob.class) .withIdentity("dbJob") .storeDurably() .build(); } @Bean public Trigger trigger(JobDetail jobDetail) { return TriggerBuilder.newTrigger() .forJob(jobDetail) .withIdentity("dbTrigger") .withSchedule(CronScheduleBuilder.cronSchedule("0 0/1 * * * ?")) // Runs every minute .build(); } }
Step 4: Define a Job
Create a Quartz job that stores logs in a database:
import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Component public class DatabaseQuartzJob implements Job { private static final Logger logger = LoggerFactory.getLogger(DatabaseQuartzJob.class); @Override public void execute(JobExecutionContext context) throws JobExecutionException { logger.info("Executing Database Quartz Job - " + System.currentTimeMillis()); } }
Step 5: Run the Application
Start your Spring Boot application, and you will see logs in the database and console:
INFO: Executing Database Quartz Job - 1742461800022 INFO: Executing Database Quartz Job - 1742461860011
Query data from Table QUARTZ_
select * from public.qrtz_scheduler_state

select * from public.qrtz_job_details

select * from public.qrtz_triggers

Comparison: With vs. Without Database

Conclusion
Quartz Scheduler is a powerful tool for scheduling jobs in Spring Boot applications. Using in-memory storage is ideal for simple, non-persistent tasks, while a database-backed approach is better for persistence, clustering, and enterprise applications.
To choose the best approach, consider your application’s needs:
- Use in-memory for lightweight, temporary tasks.
- Use database-backed scheduling for persistent, fault-tolerant jobs.