Spring Framework
@Scheduled
Spring Profiles
Java
Spring Boot

How to enable Scheduled jobs by profile in spring?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

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 illustration
Course illustration

All Rights Reserved.