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
      • Aspire Hosting
      • ASP.NET Core Integration
      • HTTP API
      • HTTP Client
      • Dashboard
      • Dashboard Agent
      • Dashboard Host
      • 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

Dashboard Host

The dashboard as a program of its own, configured from settings alone (4.8). It fronts schedulers over their HTTP API, reads every scheduler in a database, and accepts workers that dial in as agents. One program, two distributions:

Get itSettings from
dotnet tooldotnet tool install --global Quartz.Dashboard.Host, then quartz-dashboardArguments, environment variables, appsettings.json in the working directory
Container imageghcr.io/quartznet/quartz-dashboardEnvironment variables, appsettings.json mounted at /app

From an Aspire AppHost, use Aspire Hosting, which runs the image and writes its settings.

Running it

quartz-dashboard --urls http://localhost:5000 \
  --Quartz:Dashboard:Authentication:Mode=Token \
  --Quartz:Dashboard:Authentication:Tokens:Administrator=<32 random characters> \
  --Quartz:Dashboard:Targets:orders:ConnectionString="Host=db;Database=quartz;Username=quartz;Password=…"
docker run -p 8080:8080 \
  -e Quartz__Dashboard__Authentication__Mode=Token \
  -e Quartz__Dashboard__Authentication__Tokens__Administrator=<32 random characters> \
  -e Quartz__Dashboard__Targets__orders__ConnectionString="Host=db;Database=quartz;Username=quartz;Password=…" \
  ghcr.io/quartznet/quartz-dashboard:4.8.0

Open /quartz and sign in with the token. Every key below is under Quartz:Dashboard, written Quartz__Dashboard__… as an environment variable.

PathWhat it is
/quartzThe dashboard (DashboardPath). / redirects here
/login, /logoutSign-in and sign-out (Token mode)
/quartz/agentsThe agent hub, when an agent token is set
/healthzAnonymous liveness: 200 Healthy while the process answers. It asks no target and no database

Authentication

Authentication:Mode is required. Without it the host refuses to start: it logs event 9402 and exits with code 1, as it does for any other mistake in its settings.

ModeWho signs inSettings
TokenWhoever presents a token on the sign-in form, at that token's roleTokens:Viewer, Tokens:Operator, Tokens:Administrator (at least one, 16+ characters, all different); AllowTokenInUrl
OpenIdConnectUsers of an identity provider, at the role Roles:* maps theirs toAuthority, ClientId, ClientSecret, Scopes, NameClaimType (name), RoleClaimType (roles), RequireHttpsMetadata (true)
UnsecuredEvery visitor, without a credentialUnsecuredAccess: View (default) or Operate, never Administer
  • The roles are the operator roles. A viewer reads, an operator also pauses, resumes, triggers and interrupts, an administrator also adds, edits and deletes. The host builds the policy with RequireSchedulerRoles.
  • Token mode compares tokens in constant time and signs the visitor in with an HttpOnly, SameSite=Strict cookie for eight hours, renewed while in use. AllowTokenInUrl=true also accepts /login?t=<token>, and moves the browser on to an address without it. Off by default; Aspire Hosting sets it for its sign-in link.
  • OpenIdConnect mode needs Roles:Viewers, Roles:Operators or Roles:Administrators, the provider's role values; without them the host refuses to start. Its cookie is SameSite=Lax: the provider sends the browser back from another site. Register {host}/signin-oidc as the redirect URI.
  • Unsecured mode logs warning 9401 at every start. Use it on a network where every visitor is already trusted.
  • Roles:Operations:<operation> moves an operation to Operate or Administer in every mode: Roles:Operations:AddCalendar=Operate. A name the HTTP API does not publish refuses the start. In Unsecured mode the host also refuses to start when an entry lowers an operation that is Administer by default (AddJob, DeleteJob, Shutdown) to Operate: an anonymous visitor is never given an Administer operation. Raising an operation to Administer stays allowed.

The host never logs a token: the hosting layer's request lines, which carry the address and its query, are held at Warning whatever Logging says, per-provider settings such as Logging:Console:LogLevel included.

Targets

Targets:<name> is one target, and <name> is the first half of each scheduler's identity on the dashboard (orders/OrdersScheduler). It cannot contain / or +. A target is a scheduler's HTTP API or a database; saying both refuses the start.

HTTP target keyDefaultWhat it is
UrlrequiredThe HTTP API's base address: https://orders.internal/quartz-api/
SchedulerNamerequiredThe remote scheduler's name
BearerToken—Sent as Authorization: Bearer
Headers:<header>—Sent on every request
Timeout100 sThe HttpClient timeout
Store-attached target keyDefaultWhat it is
ConnectionString—The database, or name one with ConnectionStringName
ConnectionStringName—A ConnectionStrings:<name> entry in the host's own settings
ProviderinferredNpgsql, SqlServer, MySqlConnector, OracleODPManaged, SQLite-Microsoft or Firebird
TablePrefixQRTZ_The nodes' table prefix
SerializerSystemTextJsonSystemTextJson or Newtonsoft, whichever the nodes write with
ExecutionHistoryfalseThe nodes keep their history in the database (UseExecutionHistory())
RediscoveryInterval00:01:00How often the database is asked which schedulers it holds; 00:00:00 asks once
  • The provider is inferred from the connection string's keywords, by the rules Quartz.Aspire uses. An ambiguous string refuses the start; set Provider. MySql and SQLite are read with MySqlConnector and Microsoft.Data.Sqlite, the drivers the host carries.
  • A store-attached target reads the job data types Quartz writes itself. The host does not have the application's types, so a job data map holding one is shown as unreadable.
  • What a store-attached target can and cannot do is in Store-attached targets.

Agents

Agents:Tokens:Primary makes the host accept agents at {DashboardPath}/agents. A worker calls UseDashboardAgent() with Quartz:DashboardAgent:Endpoint, Token and Target set.

KeyDefaultWhat it is
Agents:Tokens:Primary—The token agents present. Set it to accept agents
Agents:Tokens:Secondary—A second token, while a rotation is under way
Agents:HeartbeatInterval00:00:15How often agents report
Agents:OfflineAfterMissedHeartbeats3Missed heartbeats before an agent is shown as unknown
Agents:OperationTimeout00:00:30How long one request through an agent may take
Agents:MaxMessageBytes4 MBThe largest answer an agent may send
Agents:ForgetAfter01:00:00How long a disconnected agent stays listed

Run one instance while the host accepts agents. Their connections and the answers in flight are in that process's memory.

The dashboard and the process

KeyDefaultWhat it is
DashboardPath/quartzWhere the dashboard is served
ReadOnlyfalseHide and refuse every change, whatever the visitor's role
ClusterDetectionInterval00:01:00How often targets are merged into clusters; 00:00:00 never
HistoryRetention1.00:00:00How far back the dashboard's own history store keeps executions
HistoryMaxEntriesPerScheduler2000How many executions and misfires per scheduler
DataProtection:KeysPath—A directory for the data protection keys, so sign-ins survive a restart. Mount a volume there in a container
  • Telemetry: with OTEL_EXPORTER_OTLP_ENDPOINT set, Quartz's spans and instruments, ASP.NET Core's instruments and the logs go to that collector. ASP.NET Core's request spans are not exported: a span carries the address, and an address can carry a token.
  • Logs: events 9400 to 9409, listed in Log Events. 9400 says at start what the host serves, and 9402 each reason it will not start.
  • Behind a reverse proxy, set ASPNETCORE_FORWARDEDHEADERS_ENABLED=true so the cookie and the OpenID Connect redirect see the original scheme and host.

The container image

Imageghcr.io/quartznet/quartz-dashboard
TagsA release X.Y.Z; and X.Y, X and latest when it is the newest of its line. A prerelease, its exact version only. Nothing is published from a branch
Architectureslinux/amd64 and linux/arm64, one index
Basemcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled-extra: no shell, ICU and time zones included
UserThe base image's non-root app user
Port8080
HealthGET /healthz. The image has no shell, so the probe is the orchestrator's

Every image carries a GitHub build provenance attestation. To check one:

gh attestation verify oci://ghcr.io/quartznet/quartz-dashboard:4.8.0 --owner quartznet

Limitations

  • One instance while it accepts agents, as above.
  • Store-attached targets read Quartz's own job data types, as above.
  • No HTTP API. The host serves the dashboard only; the fleet API through the host is #4218.
  • The operator's identity is not forwarded. An HTTP target sees the target's BearerToken, and an agent the agent token, whoever is signed in. A visitor's rights are the lower of their role and what the target allows.
Help us by improving this page!
Last Updated: 11/3/26, 9:04 PM
Contributors: Marko Lahma, Claude Opus 5.5
Prev
Dashboard Agent
Next
Hosted Services Integration