Quartz.NETQuartz.NET
Home
Features
Blog
Discussions
NuGet
GitHub
Home
Features
Blog
Discussions
NuGet
GitHub
  • Getting Started

    • Overview
    • Quartz 4 Quick Start
    • Tutorial
      • Using Quartz
      • Jobs And Triggers
      • More About Jobs & JobDetails
      • Job Data
      • More About Triggers
      • Querying Jobs and Triggers
      • Simple Triggers
      • Cron Triggers
      • RecurrenceTrigger
      • Time and TimeProvider
      • Trigger and Job Listeners
      • Scheduler Listeners
      • Job Execution Middleware
      • Job Stores
      • Configuration, Resource Usage and Building a Scheduler
      • Building a Scheduler Without a Host
      • Clustering
      • Execution Groups
      • Node Affinity (Preferred Node)
      • Testing
      • Compile-Time Checks
      • Declaring Jobs with Attributes
      • Delegate Jobs
    • Configuration Reference
    • JSON Configuration
    • Cron Expression Reference
    • Multi-Tenancy
    • Comparison
    • Frequently Asked Questions
    • Best Practices
    • Before You Go Live
    • Operating a Cluster
    • Log Events
    • Tenancy Patterns
    • Database Schema
    • Database Schema Changes
    • Migration Guide
    • Troubleshooting
    • API Documentation
  • How To's
    • One-Off Job
    • Rescheduling Jobs
    • Backfill
    • Retrying Failed Jobs
    • Pausing with a Reason
    • Job Continuations
    • Overlap Policy
    • Progress and Execution Logs
    • Job Outcomes
    • Multiple Triggers
    • Job Template
    • Running Quartz under Aspire
    • Quartz.NET with Wolverine
    • Coming from Hangfire
    • Coming from TickerQ
    • Embedding Quartz in a Library
    • Running under an External Leader Election
    • Publishing Trimmed and Native AOT
    • Extending Quartz: what is open, what is closed, and how to ask
    • A Job Store of Your Own
    • A Driver Delegate for a New Database
    • Persisting a Custom Trigger Type
    • A Lock Handler of Your Own
  • Packages

    • Quartz Core Additions

      • Jobs
      • Serialization (System.Text.Json)
      • JSON Serialization
      • Plugins
    • Integrations

      • Aspire Integration
      • ASP.NET Core Integration
      • HTTP API
      • HTTP Client
      • Dashboard
      • Dashboard Agent
      • Hosted Services Integration
      • Microsoft DI Integration
      • Multiple Schedulers with Microsoft DI
      • Observability
      • Redis Lock Handler
      • TimeZoneConverter Integration
      • Weasel Schema Management
    • 3rd Party Plugins for Quartz
  • Quartz 3.x

    • Getting Started

      • Quartz 3 Quick Start
      • Tutorial
        • Using Quartz
        • Library Overview
        • Jobs And Triggers
        • More About Jobs
        • More About Triggers
        • Execution Groups
        • Node Affinity (Preferred Node)
        • Simple Triggers
        • Cron Triggers
        • RecurrenceTrigger
        • Trigger and Job Listeners
        • Scheduler Listeners
        • Job Stores
        • Tuning the Scheduler
        • Configuration, Resource Usage and SchedulerFactory
        • Advanced (Enterprise) Features
      • Configuration Reference
      • JSON Configuration
      • Multi-Tenancy
      • Frequently Asked Questions
      • Best Practices
      • Tenancy Patterns
      • Troubleshooting
      • API Documentation
      • Database Schema
      • Database Schema Changes
      • Migration Guide
      • Miscellaneous Features
    • How To's

      • One-Off Job
      • Multiple Triggers
      • Job Template
      • Using the CronTrigger
      • Rescheduling Jobs
    • Packages

      • Quartz Core Additions

        • Dashboard
        • Jobs
        • Serialization (System.Text.Json)
        • Serialization (Newtonsoft Json.NET)
        • Plugins
      • Integrations

        • ASP.NET Core Integration
        • Hosted Services Integration
        • Microsoft DI Integration
        • Multiple Schedulers with Microsoft DI
        • OpenTelemetry Integration
        • OpenTracing Integration
        • Redis Lock Handler
        • TimeZoneConverter Integration
      • 3rd Party Plugins for Quartz
  • Old Releases

    • Quartz 2.x
      • Quartz 2 Quick Start
      • Tutorial
        • Lesson 1: Using Quartz
        • Lesson 2: Jobs And Triggers
        • Lesson 3: More About Jobs & JobDetails
        • Lesson 4: More About Triggers
        • Lesson 5: SimpleTrigger
        • Lesson 6: CronTrigger
        • Lesson 7: TriggerListeners and JobListeners
        • Lesson 8: SchedulerListeners
        • Lesson 9: JobStores
        • Lesson 10: Configuration, Resource Usage and SchedulerFactory
        • Lesson 11: Advanced (Enterprise) Features
        • Lesson 12: Miscellaneous Features of Quartz
        • CronTrigger Tutorial
      • Configuration Reference
      • Migration Guide
      • API Documentation
    • Quartz 1.x
      • Tutorial
        • Lesson 1: Using Quartz
        • Lesson 2: Jobs And Triggers
        • Lesson 3: More About Jobs & JobDetails
        • Lesson 4: More About Triggers
        • Lesson 5: SimpleTrigger
        • Lesson 6: CronTrigger
        • Lesson 7: TriggerListeners and JobListeners
        • Lesson 8: SchedulerListeners
        • Lesson 9: JobStores
        • Lesson 10: Configuration, Resource Usage and SchedulerFactory
        • Lesson 11: Advanced (Enterprise) Features
        • Lesson 12: Miscellaneous Features of Quartz
      • API Documentation
  • License

Configuration, Resource Usage and Building a Scheduler

A scheduler is assembled from a thread pool, a job store, the data sources that store needs, and its own settings. The service container puts them together; AddQuartz is where you choose them.

ComponentConfigure with
thread poolq.UseDefaultThreadPool(20), or q.UseThreadPool<T>() for your own
job store (Job Stores)q.UseInMemoryStore() or q.UsePersistentStore(…)
data sources, for a persistent storethe same UsePersistentStore call
the scheduler: name, id, idle wait time, batchingq.ConfigureScheduler(options => …)

DefaultThreadPool runs jobs as tasks on the CLR's managed thread pool. Its one setting, MaxConcurrency, limits how many jobs a node runs at once.

Every option, in both its typed and its flat spelling, is in the configuration reference.

Building a scheduler without a container

An application with no host (a console application, a test) builds a scheduler with QuartzSchedulerBuilder. Its Create callback is the AddQuartz callback over a container it creates itself, so the same configuration works in both:

IScheduler scheduler = await QuartzSchedulerBuilder
    .Create(q => q
        .ConfigureScheduler(options => options.InstanceName = "reporting")
        .UseDefaultThreadPool(maxConcurrency: 10)
        .UseInMemoryStore())
    .BuildScheduler();

Every configuration method returns the builder, so the whole thing is one expression. Nothing starts on its own: without a hosted service, you start and shut down the scheduler.

Building a Scheduler Without a Host covers Build() versus BuildScheduler(), disposal of the container, persistent and clustered standalone schedulers, and what the container-first path adds.

Configuring from properties

A scheduler can also be configured from flat quartz.* properties (NameValueCollection), usually loaded from a file, or created by your program:

await using StandaloneSchedulerFactory schedulerFactory = QuartzSchedulerBuilder.Create()
    .UseProperties(properties)
    .Build();
  • The keys become the same options and registrations the code API produces, so the scheduler is the same.
  • Properties and code can be mixed; code wins.
  • Keys are checked against the ones Quartz reads, so a misspelling is reported instead of leaving a setting at its default.

Every key and the option it maps to: Legacy property keys.

Logging

Quartz logs through Microsoft.Extensions.Logging. A scheduler built from a container, such as under a host, uses the application's logging with no setup. Quartz logs some information while starting, then only serious problems while jobs run.

That covers everything the container builds: the scheduling loop, the job store with its cluster manager and misfire handler, the thread pool, the job factory. It does not cover:

  • what no container builds: a listener or trigger you constructed, the static helpers, the jobs in Quartz.Jobs;
  • a scheduler built by QuartzSchedulerBuilder, whose container has no logging providers unless you register some on its Services.

For those, set the logger factory with one call:

// obtain your logger factory, for example from IServiceProvider
ILoggerFactory loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();

LogProvider.SetLogProvider(loggerFactory);

LogProvider is in Quartz.Diagnostics. It also creates loggers for the same situation: LogProvider.CreateLogger<T>().

Help us by improving this page!
Last Updated: 10/19/26, 11:26 PM
Contributors: Marko Lahma, Claude Opus 5.5
Prev
Job Stores
Next
Building a Scheduler Without a Host