Quartz 4.0.0-alpha.1


title: Quartz 4 Quick Start

Welcome to the Quick Start Guide for Quartz.NET. As you read this guide, expect to see details of:

  • Installing Quartz.NET
  • Configuring Quartz to your own particular needs
  • Running a first job, in a console application and under a host

Install

dotnet add package Quartz

That is everything a scheduler needs. Dependency injection, hosting and System.Text.Json serialization are part of the core package — 3.x shipped them as Quartz.Extensions.DependencyInjection, Quartz.Extensions.Hosting and Quartz.Serialization.Json.

The optional packages, added the same way when you want them:

Package For
Quartz.Serialization.Newtonsoft persisting with Newtonsoft.Json instead of System.Text.Json
Quartz.Jobs the ready-made jobs — file scanning, sending mail, running a process
Quartz.Plugins history logging, XML/JSON schedule files, the interrupt monitor
Quartz.AspNetCore health checks and the HTTP API
Quartz.Dashboard the web dashboard

Configuration

Quartz is configured with strongly typed options. An option has the same name in code and in configuration files, so there is one vocabulary to learn.

In an application with a host

Most applications register Quartz into their service collection:

builder.AddQuartz(q =>
{
    q.ConfigureScheduler(options => options.InstanceName = "MyScheduler");

    // default max concurrency is 10
    q.UseDefaultThreadPool(maxConcurrency: 5);

    q.UsePersistentStore(store =>
    {
        // there are other databases supported too
        store.UseSqlServer("my connection string");
        store.UseClustering();

        // System.Text.Json is built in; the Newtonsoft one is a package away
        store.UseSystemTextJsonSerializer();

        store.Configure(options =>
        {
            // store job data as strings, which avoids surprises when a serialized
            // type changes shape later
            options.StoreJobDataAsStrings = true;
        });
    });

    // reads jobs and triggers from XML; requires the Quartz.Plugins package
    q.UseXmlSchedulingConfiguration(x =>
    {
        x.Files.Add("~/quartz_jobs.xml");
        x.FailOnFileNotFound = true;
        x.FailOnSchedulingError = true;
    });
});

builder.AddQuartzHostedService(options => options.WaitForJobsToComplete = true);

The hosted service starts the scheduler with the application and shuts it down with it.

Without a host

Console applications and tests build a scheduler directly. The configuration API is the same, and the whole chain is one expression:

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

await scheduler.Start();

From configuration files

Settings can come from appsettings.json, or anywhere else IConfiguration reads from, using the same names:

{
  "Quartz": {
    "Scheduler": { "InstanceName": "MyScheduler" },
    "ThreadPool": { "MaxConcurrency": 3 }
  }
}

builder.AddQuartz(...) reads that section by itself. On a bare IServiceCollection, name it:

services.AddQuartz(configuration.GetSection("Quartz"));

Flat quartz.* keys from earlier versions are still accepted and mean the same thing. Full details are in the Quartz Configuration Reference.

The scheduler created by this configuration has the following characteristics:

  • Scheduler:InstanceName - This scheduler's name will be "MyScheduler".
  • ThreadPool:MaxConcurrency - Maximum of 3 jobs can be run simultaneously (default is 10).
  • No job store is configured, so Quartz's data — jobs, triggers and their state — is held in memory rather than in a database.

Even if you intend to use a database, it is worth getting Quartz working with the in-memory store first, before adding a second thing that can go wrong.

Actually you don't need to define these properties if you don't want to, Quartz.NET comes with sane defaults

A first console application

The following program builds a scheduler with the default configuration, starts it, and shuts it down:

Program.cs

using Quartz;

// Build a scheduler with the default configuration
IScheduler scheduler = await QuartzSchedulerBuilder.Create().BuildScheduler();

// and start it off
await scheduler.Start();

// some sleep to show what's happening
await Task.Delay(TimeSpan.FromSeconds(10));

// and last shut down the scheduler when you are ready to close your program
await scheduler.Shutdown();

Your application terminates once there is no code left to execute after scheduler.Shutdown(): a running scheduler does not keep the process alive on its own. Block explicitly — or use the host, which does the blocking for you — if the scheduler should keep running.

Run it now and nothing happens: ten seconds pass and the program ends. Let us add some logging.

Adding logging

Quartz logs through Microsoft.Extensions.Logging. Under a host it uses whatever the application already configured, and there is nothing to do. A console application with no host tells Quartz where to log by handing LogProvider a logger factory:

using Microsoft.Extensions.Logging;
using Quartz.Diagnostics;

ILoggerFactory loggerFactory = LoggerFactory.Create(logging => logging
    .SetMinimumLevel(LogLevel.Debug)
    .AddSimpleConsole(options =>
    {
        options.SingleLine = true;
        options.TimestampFormat = "HH:mm:ss ";
    }));

LogProvider.SetLogProvider(loggerFactory);

Trying out the application and adding jobs

Now starting the application says considerably more:

12:51:10 info: Quartz.Core.QuartzScheduler[0] Quartz Scheduler created
12:51:10 info: Quartz.Impl.RAMJobStore[0] RAMJobStore initialized.
12:51:10 info: Quartz.Impl.DefaultSchedulerFactory[0] Quartz Scheduler 4.0.0.0 - 'MyScheduler' with instanceId 'NON_CLUSTERED' initialized
12:51:10 info: Quartz.Impl.DefaultSchedulerFactory[0] Using thread pool 'Quartz.Impl.DefaultThreadPool', size: 10
12:51:10 info: Quartz.Impl.DefaultSchedulerFactory[0] Using job store 'Quartz.Impl.RAMJobStore', supports persistence: False, clustered: False
12:51:10 info: Quartz.Core.QuartzScheduler[0] Scheduler MyScheduler_$_NON_CLUSTERED started.

We need a simple test job to try the scheduler out; let's create a HelloJob that greets the console.

public sealed class HelloJob : IJob
{
    public async ValueTask Execute(IJobExecutionContext context, CancellationToken cancellationToken = default)
    {
        await Console.Out.WriteLineAsync("Greetings from HelloJob!");
    }
}

To do something interesting, add code just after Start(), before the Task.Delay:

// define the job and tie it to our HelloJob class
IJobDetail job = JobBuilder.Create<HelloJob>()
    .WithIdentity("job1", "group1")
    .Build();

// Trigger the job to run now, and then repeat every 10 seconds
ITrigger trigger = TriggerBuilder.Create()
    .WithIdentity("trigger1", "group1")
    .StartNow()
    .WithSimpleSchedule(x => x
        .WithInterval(TimeSpan.FromSeconds(10))
        .RepeatForever())
    .Build();

// Tell Quartz to schedule the job using our trigger
await scheduler.ScheduleJob(job, trigger);

// several triggers for one job go together, in one call
// await scheduler.ScheduleJob(job, [trigger1, trigger2], new ScheduleJobOptions { Replace = true });

The complete console application now looks like this:

using Microsoft.Extensions.Logging;

using Quartz;
using Quartz.Diagnostics;

ILoggerFactory loggerFactory = LoggerFactory.Create(logging => logging
    .SetMinimumLevel(LogLevel.Debug)
    .AddSimpleConsole(options =>
    {
        options.SingleLine = true;
        options.TimestampFormat = "HH:mm:ss ";
    }));

LogProvider.SetLogProvider(loggerFactory);

// Build a scheduler with the default configuration
IScheduler scheduler = await QuartzSchedulerBuilder.Create().BuildScheduler();

await scheduler.Start();

IJobDetail job = JobBuilder.Create<HelloJob>()
    .WithIdentity("job1", "group1")
    .Build();

ITrigger trigger = TriggerBuilder.Create()
    .WithIdentity("trigger1", "group1")
    .StartNow()
    .WithSimpleSchedule(x => x
        .WithInterval(TimeSpan.FromSeconds(10))
        .RepeatForever())
    .Build();

await scheduler.ScheduleJob(job, trigger);

// let it run for a while
await Task.Delay(TimeSpan.FromSeconds(60));

await scheduler.Shutdown();

public sealed class HelloJob : IJob
{
    public async ValueTask Execute(IJobExecutionContext context, CancellationToken cancellationToken = default)
    {
        await Console.Out.WriteLineAsync("Greetings from HelloJob!");
    }
}

Creating and initializing the database

To use SQL persistence, and features such as clustering that depend on it, create a database for Quartz and then create its tables and indexes.

The DDL scripts are in the Quartz.NET repository, one per database. Upgrading a schema created by an earlier version is a different script — see Database Schema Changes. What the tables hold is described in Database.

Now go have some fun exploring Quartz.NET. Continue with the tutorial.

Showing the top 20 packages that depend on Quartz.

Packages Downloads
Quartz.Extensions.DependencyInjection
Quartz.NET Microsoft.Extensions.DependencyInjection integration; Quartz Scheduling Framework for .NET
125
Quartz.Extensions.DependencyInjection
Quartz.NET Microsoft.Extensions.DependencyInjection integration; Quartz Scheduling Framework for .NET
126
Quartz.Extensions.DependencyInjection
Quartz.NET Microsoft.Extensions.DependencyInjection integration; Quartz Scheduling Framework for .NET
127
Quartz.Extensions.DependencyInjection
Quartz.NET Microsoft.Extensions.DependencyInjection integration; Quartz Scheduling Framework for .NET
128
Quartz.Extensions.DependencyInjection
Quartz.NET Microsoft.Extensions.DependencyInjection integration; Quartz Scheduling Framework for .NET
130
Quartz.Extensions.DependencyInjection
Quartz.NET Microsoft.Extensions.DependencyInjection integration; Quartz Scheduling Framework for .NET
134
Quartz.Extensions.DependencyInjection
Quartz.NET Microsoft.Extensions.DependencyInjection integration; Quartz Scheduling Framework for .NET
137
Quartz.Extensions.DependencyInjection
Quartz.NET Microsoft.Extensions.DependencyInjection integration; Quartz Scheduling Framework for .NET
152
Quartz.Extensions.Hosting
Quartz.NET Generic Host integration; Quartz Scheduling Framework for .NET
137
Quartz.Extensions.Hosting
Runs Quartz.net as a HostedService in a generic host.
126
Quartz.Serialization.Json
Quartz.NET JSON Serialization Support
130
Quartz.Serialization.Json
Quartz.NET JSON Serialization Support; Quartz Scheduling Framework for .NET
126
Quartz.Serialization.Json
Quartz.NET JSON Serialization Support; Quartz Scheduling Framework for .NET
127
Quartz.Serialization.Json
Quartz.NET JSON Serialization Support; Quartz Scheduling Framework for .NET
128

https://github.com/quartznet/quartznet/releases

Version Downloads Last updated
4.0.0-alpha.3 2 08/28/2026
4.0.0-alpha.2 4 08/27/2026
4.0.0-alpha.1 7 08/22/2026
3.20.0 1 08/28/2026
3.19.1 20 07/26/2026
3.19.0 18 07/25/2026
3.18.2 25 06/27/2026
3.18.1 41 04/25/2026
3.18.0 43 04/11/2026
3.17.1 47 04/03/2026
3.17.0 44 03/29/2026
3.16.1 43 03/05/2026
3.16.0 45 03/02/2026
3.15.1 92 10/28/2025
3.15.0 137 08/05/2025
3.14.0 131 04/01/2025
3.13.1 124 04/01/2025
3.13.0 118 04/01/2025
3.12.0 143 04/01/2025
3.11.0 139 04/01/2025
3.10.0 123 04/01/2025
3.9.0 113 04/01/2025
3.8.1 98 04/01/2025
3.8.0 122 04/01/2025
3.7.0 113 04/01/2025
3.6.3 127 04/01/2025
3.6.2 121 04/01/2025
3.6.1 140 04/01/2025
3.6.0 126 04/01/2025
3.5.0 126 04/01/2025
3.4.0 132 04/01/2025
3.3.3 104 04/01/2025
3.3.2 119 04/01/2025
3.3.1 136 04/01/2025
3.3.0 126 04/05/2025
3.2.4 113 04/01/2025
3.2.3 122 04/01/2025
3.2.2 123 04/01/2025
3.2.1 113 04/01/2025
3.2.0 121 04/01/2025
3.1.0 124 04/01/2025
3.0.7 119 04/01/2025
3.0.6 123 04/01/2025
3.0.5 123 04/01/2025
3.0.4 133 04/01/2025
3.0.3 126 04/01/2025
3.0.2 110 04/01/2025
3.0.1 119 04/01/2025
3.0.0 132 04/01/2025
2.6.2 120 04/01/2025
2.6.1 115 04/01/2025
2.6.0 129 04/01/2025
2.5.0 131 04/01/2025
2.4.1 136 04/01/2025
2.4.0 125 04/01/2025
2.3.3 113 04/01/2025
2.3.2 141 04/01/2025
2.3.1 124 04/01/2025
2.3.0 138 04/01/2025
2.2.4 132 04/01/2025
2.2.3 124 04/01/2025
2.2.2 113 04/01/2025
2.2.1 121 04/01/2025
2.2.0 145 04/01/2025
2.1.2 123 04/01/2025
2.1.1 120 04/01/2025
2.1.0 125 04/01/2025
2.0.1 124 04/01/2025
2.0.0 130 04/01/2025
1.0.3 129 04/01/2025