Quartz 4.0.0-alpha.1
Prefix Reserveddotnet add package Quartz --version 4.0.0-alpha.1
NuGet\Install-Package Quartz -Version 4.0.0-alpha.1
<PackageReference Include="Quartz" Version="4.0.0-alpha.1" />
<PackageVersion Include="Quartz" Version="4.0.0-alpha.1" />
<PackageReference Include="Quartz" />
paket add Quartz --version 4.0.0-alpha.1
#r "nuget: Quartz, 4.0.0-alpha.1"
#:package Quartz@4.0.0-alpha.1
#addin nuget:?package=Quartz&version=4.0.0-alpha.1&prerelease
#tool nuget:?package=Quartz&version=4.0.0-alpha.1&prerelease
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.
::: tip 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.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.DependencyInjection (>= 10.0.11)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.11)
- Microsoft.Extensions.Logging (>= 10.0.11)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.11)
NuGet packages (907)
Showing the top 5 NuGet packages that depend on Quartz:
| Package | Downloads |
|---|---|
|
Quartz.Extensions.DependencyInjection
Quartz.NET Microsoft.Extensions.DependencyInjection integration; Quartz Scheduling Framework for .NET |
|
|
Quartz.Serialization.Json
Quartz.NET JSON Serialization Support; Quartz Scheduling Framework for .NET |
|
|
Quartz.AspNetCore
Quartz.NET ASP.NET Core integration; Quartz Scheduling Framework for .NET |
|
|
MassTransit.Quartz
MassTransit Quartz.NET scheduler support; MassTransit provides a developer-focused, modern platform for creating distributed applications without complexity. |
|
|
WasmAI.AutoGenerator
is a powerful code-generation library for .NET 8 that automates the scaffolding of backend components like models, services, controllers, and more—based on a flexible folder configuration. |
GitHub repositories (107)
Showing the top 20 popular GitHub repositories that depend on Quartz:
| Repository | Stars |
|---|---|
|
bitwarden/server
Bitwarden infrastructure/backend (API, database, Docker, etc).
|
|
|
abpframework/abp
Open-source web application framework for ASP.NET Core! Offers an opinionated architecture to build enterprise software solutions with best practices on top of the .NET. Provides the fundamental infrastructure, cross-cutting-concern implementations, startup templates, application modules, UI themes, tooling and documentation.
|
|
|
kgrzybek/modular-monolith-with-ddd
Full Modular Monolith application with Domain-Driven Design approach.
|
|
|
aspnetboilerplate/aspnetboilerplate
ASP.NET Boilerplate - Web Application Framework
|
|
|
RayWangQvQ/BiliBiliToolPro
B 站(bilibili)自动任务工具,支持docker、青龙、k8s等多种部署方式。全面拥抱AI。敏感肌也能用。
|
|
|
MassTransit/MassTransit
Distributed Application Framework for .NET
|
|
|
anjoy8/Blog.Core
💖 ASP.NET Core 8.0 全家桶教程,前后端分离后端接口,vue教程姊妹篇,官方文档:
|
|
|
Jeric-X/SyncClipboard
跨平台剪贴板同步、历史记录管理工具 / Cross-platform cipboard syncing, history management tool
|
|
|
dotnetcore/Util
Util是一个.Net平台下的应用框架,旨在提升中小团队的开发能力,由工具类、分层架构基类、Ui组件,配套代码生成模板,权限等组成。
|
|
|
dotnetcore/WTM
Use WTM to write .netcore app fast !!!
|
|
|
cq-panda/Vue.NetCore
(已支持sqlsugar).NetCore、.Net6、Vue2、Vue3、Vite、TypeScript、Element plus+uniapp前后端分离,全自动生成代码;支持移动端(ios/android/h5/微信小程序。http://www.volcore.xyz/
|
|
|
Ombi-app/Ombi
Want a Movie or TV Show on Plex/Emby/Jellyfin? Use Ombi!
|
|
|
oskardudycz/EventSourcing.NetCore
Examples and Tutorials of Event Sourcing in .NET
|
|
|
Arcenox-co/TickerQ
TickerQ is a fast, reflection-free background task scheduler for .NET built with source generators, EF Core integration, cron + time-based execution, and a real-time dashboard.
|
|
|
kgrzybek/sample-dotnet-core-cqrs-api
Sample .NET Core REST API CQRS implementation with raw SQL and DDD using Clean Architecture.
|
|
|
BookerLiu/GeekDesk
🔥小巧、美观的桌面快速启动工具 Small, beautiful desktop quickstart management tool with integrated Everything search
|
|
|
liukuo362573/YiShaAdmin
基于 .NET Core MVC 的权限管理系统,代码易读易懂、界面简洁美观
|
|
|
Cleanuparr/Cleanuparr
Advanced download manager for the Servarr ecosystem
|
|
|
BrighterCommand/Brighter
A framework for building messaging apps with .NET and C#.
|
|
|
phongnguyend/Practical.CleanArchitecture
Full-stack .Net 10 Clean Architecture (Microservices, Modular Monolith, Monolith), Blazor, Angular 22, React 19, Vue 3.5, BFF with YARP, NextJs 16, Domain-Driven Design, CQRS, SOLID, Asp.Net Core Identity Custom Storage, OpenID Connect, EF Core, OpenTelemetry, SignalR, Background Services, Health Checks, Rate Limiting, Clouds (Azure, AWS, GCP), ...
|
| Version | Downloads | Last Updated |
|---|---|---|
| 4.0.0-alpha.1 | 33 | 8/22/2026 |
| 3.19.1 | 432,098 | 7/26/2026 |
| 3.19.0 | 50,008 | 7/24/2026 |
| 3.18.2 | 780,685 | 6/27/2026 |
| 3.18.1 | 2,330,637 | 4/25/2026 |
| 3.18.0 | 590,247 | 4/11/2026 |
| 3.17.1 | 377,809 | 4/3/2026 |
| 3.17.0 | 376,555 | 3/29/2026 |
| 3.16.1 | 1,469,121 | 3/4/2026 |
| 3.16.0 | 2,494,504 | 3/1/2026 |
| 3.15.1 | 7,109,367 | 10/26/2025 |
| 3.15.0 | 4,505,219 | 8/3/2025 |
| 3.14.0 | 10,223,394 | 3/8/2025 |
| 3.13.1 | 14,648,013 | 11/2/2024 |
| 3.13.0 | 6,766,889 | 8/10/2024 |
| 3.12.0 | 720,902 | 8/3/2024 |
| 3.11.0 | 2,425,745 | 7/7/2024 |
| 3.10.0 | 730,367 | 6/26/2024 |
| 3.9.0 | 3,634,599 | 5/9/2024 |
| 3.8.1 | 6,475,917 | 2/17/2024 |