Comparison

Hangfire vs. Quartz.NET vs. TickerQ vs. BackgroundService: which .NET job framework to use

Almost every .NET application eventually needs work that runs outside of a web request: sending emails, importing files, generating reports, syncing with other systems. There are four common ways to do it — Hangfire, Quartz.NET, the younger TickerQ, and the built-in BackgroundService. They solve overlapping but different problems. This comparison helps you pick the right one for your project.

The short answer

Comparison at a glance

As of September 2026, based on each project's documentation. Details change between releases — check the current docs for anything that decides your choice.

HangfireQuartz.NETTickerQBackgroundService
Main modelJob queue + schedulerScheduler (jobs + triggers)Scheduler (“tickers”)Long-running loop in your process
PersistenceYes — SQL Server built in; PostgreSQL, Redis and others via official Pro or community packagesOptional — in-memory by default, ADO.NET job store for SQL Server, PostgreSQL, MySQL, SQLite and othersYes — via Entity Framework Core; in-memory also possibleNo
Fire-and-forget / queued jobsYesPossible via one-off triggers, not its focusYes (one-off “time tickers”)Build it yourself (e.g. with Channels)
Recurring (cron) jobsYesYes, plus simple and calendar-based triggersYesBuild it yourself (PeriodicTimer)
Automatic retriesYes, 10 attempts with back-off by defaultNo built-in retry policy; a job can request a re-fireYes, configurableNo
Built-in dashboardYesNo (community projects exist)YesNo
Survives a restartYesOnly with a persistent job storeWith persistence enabledNo — in-flight work is lost
LicenseLGPL 3.0 core, commercial Pro add-onsApache 2.0Open sourcePart of .NET
MaturityAround since 2014, very large install baseOne of the oldest .NET schedulersYoung project, growing quickly—

Hangfire: a job queue with scheduling built in

Hangfire's core idea is that calling BackgroundJob.Enqueue(() => ...) should be as easy as calling the method directly — but the call is serialized into persistent storage and executed by a worker, possibly on another server, with automatic retries if it fails. Delayed jobs, recurring jobs via cron expressions and continuations are built on the same foundation.

Strengths: very little code to get started, work survives restarts, failed jobs retry automatically, and the built-in dashboard shows queues and recent jobs. It is by far the most widely used option, so almost every problem you will hit has been hit — and answered — before.

Watch out for: the dashboard runs inside your application and only shows what the storage still holds — succeeded jobs expire after about a day by default (why, and what to do). Changing a job's method signature while old jobs are still queued breaks them. Redis storage and batches are part of the commercial Pro packages.

Quartz.NET: a scheduler first

Quartz.NET is a port of the Java Quartz scheduler and separates jobs (what to do) from triggers (when to do it). A single job can have several triggers; triggers can be cron-based, simple intervals, or combined with calendars that exclude, for example, public holidays. Misfire instructions define exactly what happens when a run was missed because the scheduler was down.

Strengths: the most expressive scheduling model of the four, clustering with a shared database job store, permissive Apache 2.0 license, and years of production use.

Watch out for: it is not a work queue — enqueueing thousands of ad-hoc jobs from your code is not what it is designed for. There is no built-in retry policy (a failing job can ask to be re-fired, but back-off and attempt limits are up to you) and no official dashboard. The default in-memory job store loses everything on restart.

TickerQ: the modern newcomer

TickerQ takes a different technical approach: jobs are discovered with source generators instead of reflection, persistence runs through Entity Framework Core, and a dashboard is available as a package. It distinguishes cron tickers (recurring) from time tickers (run once at a given time).

Strengths: a clean, modern API, good fit for applications that already use EF Core, no reflection at runtime.

Watch out for: it is a young project. Fewer people have run it through years of production edge cases, and there are fewer answered questions when something goes wrong. That is not a reason to avoid it, but it is a reason to test the failure cases you care about — restarts, deploys, concurrent servers — before you rely on it.

BackgroundService: no framework at all

ASP.NET Core's BackgroundService (an IHostedService) runs a long-lived loop inside your process. Combined with PeriodicTimer or System.Threading.Channels, it covers simple needs without any dependency.

Strengths: zero dependencies, full control, nothing to configure.

Watch out for: there is no persistence, no retry, no history and no visibility. Anything in flight when the process stops is gone. With several replicas, every replica runs the loop, so you need your own locking to avoid doing the work twice. Once you catch yourself building retries and a status table, it is time for a framework.

How to decide

  1. Must the work survive a restart or deploy? If yes, rule out a plain BackgroundService, and Quartz.NET with the in-memory store.
  2. Is most work triggered by your code (a user signs up, send an email)? Hangfire or TickerQ fit naturally.
  3. Is the schedule itself complex (business calendars, many triggers per job, strict misfire rules)? Quartz.NET.
  4. How much risk can you take on maturity? Hangfire and Quartz.NET are proven over many years; TickerQ is newer.
  5. How will you know when it stops working? Every option here can fail silently: a scheduler that stopped, a worker that crashed, a job that fails on every retry. Plan monitoring from the start — job history that survives deploys, alerts on error rates, and a heartbeat check for silence.

Monitoring, whichever you choose

Built-in dashboards show the current state inside the running application; they do not push alerts, and they disappear with the process they live in. QueueHawk covers that gap for Hangfire: an agent streams every job state change out of your application, keeps a searchable history across deploys, and alerts via Slack, Teams, email or webhook on error rates and missing heartbeats. It does not support Quartz.NET, TickerQ or hosted services today. If you schedule with cron expressions in any of them, the cron expression explainer shows exactly when a job will run.

FAQ

Is Hangfire or Quartz.NET better?

Neither is better in general. Hangfire is the stronger choice when you mainly enqueue work from your application and want retries, persistence and a dashboard out of the box. Quartz.NET is stronger when scheduling itself is the hard part: complex triggers, calendars that exclude holidays, and precise misfire handling.

Is TickerQ production-ready?

TickerQ is used in production by a growing number of teams, but it is much younger than Hangfire and Quartz.NET, so its ecosystem of storage options, integrations and answered questions is smaller. Evaluate it against your own requirements and check its release history and issue tracker before committing.

When is a plain BackgroundService enough?

When the work is cheap to lose and easy to redo: polling a queue that itself is durable, refreshing a cache, or a periodic cleanup where a missed run does not matter. As soon as work must not be lost on restart, needs retries, or needs a history, use a job framework.

Can QueueHawk monitor Quartz.NET or TickerQ?

Not today. QueueHawk's agent hooks into Hangfire's own state-change pipeline, so it currently supports Hangfire only. Support for other schedulers depends on demand; if you need it, tell us at team@queuehawk.com.

← All articles Try QueueHawk free →

Running Hangfire? See every job, across every app

History that survives deploys, error-rate and heartbeat alerts. Free for one application.

Start free