Spring Framework
@Scheduled
Spring Profiles
Java
Spring Boot

How to enable Scheduled jobs by profile in spring?

Data Structures & Algorithms practice on Codemia

Step through 300+ coding interview problems with animated visualisers that show the data structure changing as the code runs. The Blind 75 are free.

Practice algorithms

Introduction

To enable @Scheduled jobs only for specific Spring profiles, annotate the scheduling configuration class or the bean containing scheduled methods with @Profile("production"). This ensures the @Scheduled methods only run when the specified profile is active. Alternatively, use a @ConditionalOnProperty to toggle scheduling based on a property, or externalize the cron expression and set it to "-" (disabled) in non-production profiles.

Method 1: @Profile on the Configuration Class

java
1@Configuration
2@EnableScheduling
3@Profile("production")
4public class SchedulingConfig {
5    // Scheduling is only enabled when "production" profile is active
6}
java
1@Component
2public class ReportJob {
3
4    @Scheduled(cron = "0 0 8 * * MON-FRI")
5    public void generateDailyReport() {
6        System.out.println("Generating report...");
7    }
8}

With this setup, @EnableScheduling is only activated when the production profile is active. Without it, the @Scheduled annotation is ignored entirely.

Method 2: @Profile on the Scheduled Bean

java
1@Configuration
2@EnableScheduling
3public class SchedulingConfig {
4    // Always enable scheduling infrastructure
5}
6
7@Component
8@Profile("production")
9public class ProductionJobs {
10
11    @Scheduled(fixedRate = 60000)
12    public void syncInventory() {
13        System.out.println("Syncing inventory...");
14    }
15
16    @Scheduled(cron = "0 0 2 * * *")
17    public void cleanupExpiredSessions() {
18        System.out.println("Cleaning sessions...");
19    }
20}
21
22@Component
23@Profile("dev")
24public class DevJobs {
25
26    @Scheduled(fixedRate = 300000)
27    public void devHealthCheck() {
28        System.out.println("Dev health check...");
29    }
30}

This lets you define different jobs for different profiles.

Method 3: @ConditionalOnProperty

java
1@Configuration
2@EnableScheduling
3@ConditionalOnProperty(name = "app.scheduling.enabled", havingValue = "true")
4public class SchedulingConfig {
5}
yaml
1# application-production.yml
2app:
3  scheduling:
4    enabled: true
5
6# application-dev.yml
7app:
8  scheduling:
9    enabled: false

This is more flexible than @Profile because it does not tie scheduling to a specific profile name.

Method 4: Externalized Cron Expressions

Set the cron expression to "-" (disabled cron) per profile:

java
1@Component
2public class ReportJob {
3
4    @Scheduled(cron = "${app.report.cron}")
5    public void generateReport() {
6        System.out.println("Generating report...");
7    }
8}
yaml
1# application-production.yml
2app:
3  report:
4    cron: "0 0 8 * * MON-FRI"
5
6# application-dev.yml
7app:
8  report:
9    cron: "-"  # Disabled — Spring recognizes "-" as "do not schedule"

The special cron value "-" was introduced in Spring 5.1 and disables the scheduled task entirely.

Method 5: Programmatic Scheduling

For full control, configure tasks programmatically:

java
1@Configuration
2@EnableScheduling
3public class DynamicSchedulingConfig implements SchedulingConfigurer {
4
5    @Value("${spring.profiles.active:default}")
6    private String activeProfile;
7
8    @Override
9    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
10        if ("production".equals(activeProfile)) {
11            taskRegistrar.addCronTask(
12                () -> System.out.println("Production job running"),
13                "0 0 8 * * MON-FRI"
14            );
15        }
16
17        if ("dev".equals(activeProfile)) {
18            taskRegistrar.addFixedRateTask(
19                () -> System.out.println("Dev job running"),
20                60000
21            );
22        }
23    }
24}

Setting the Active Profile

bash
1# Command line
2java -jar myapp.jar --spring.profiles.active=production
3
4# Environment variable
5export SPRING_PROFILES_ACTIVE=production
6
7# application.properties
8spring.profiles.active=production
yaml
1# application.yml
2spring:
3  profiles:
4    active: production

Approach Comparison

ApproachGranularityFlexibilitySpring Version
@Profile on config classAll jobs on/offLowAny
@Profile on beanPer-beanMediumAny
@ConditionalOnPropertyAll jobs on/offHighSpring Boot
Cron "-"Per-jobHighSpring 5.1+
SchedulingConfigurerPer-jobHighestAny

Common Pitfalls

  • Putting @Profile on individual @Scheduled methods instead of the bean or config class: @Profile is a bean-level annotation — it controls whether the bean is created, not individual methods. Annotating a method with @Profile has no effect. Put it on the @Component class or the @Configuration class.
  • Enabling @EnableScheduling globally without profile awareness: If @EnableScheduling is on your main application class (not a profiled config), scheduling infrastructure is always active. Move it to a separate @Configuration class with @Profile or @ConditionalOnProperty.
  • Using "-" as a cron expression on Spring versions before 5.1: The "-" disable feature was added in Spring 5.1 (Spring Boot 2.1). On older versions, "-" is treated as an invalid cron expression and throws IllegalArgumentException at startup.
  • Forgetting that @Scheduled requires a no-arg void method: The method annotated with @Scheduled must return void and take no arguments. If the method has parameters, Spring silently ignores the scheduling annotation.
  • Not setting a thread pool for scheduled tasks: By default, Spring uses a single-thread executor for all @Scheduled tasks. If one task blocks, all others are delayed. Configure a pool with spring.task.scheduling.pool.size=5 or define a custom TaskScheduler bean.

Summary

  • Use @Profile("production") on the @EnableScheduling config class to disable all jobs in non-production environments
  • Use @Profile on individual @Component beans to enable different jobs per profile
  • Use @ConditionalOnProperty for property-based toggling independent of profile names
  • Use cron expression "-" (Spring 5.1+) to disable individual jobs per profile
  • Always configure a thread pool size for scheduled tasks to avoid single-thread bottlenecks

Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Data Structures & Algorithms practice on Codemia

Step through 300+ coding interview problems with animated visualisers that show the data structure changing as the code runs. The Blind 75 are free.

Practice algorithms