How */5 * * * * works
*/5 in the minute field means every minute from 0 to 59 that is a multiple of 5: :00, :05, :10, :15, :20 and so on. The schedule follows the clock, not the moment your app started: a job registered at 10:03 first runs at 10:05.
A step that does not divide 60 restarts every hour. */7 * * * * runs at :49 and :56, and then at :00, only four minutes later.
Variations
| Schedule | Hangfire / crontab | Azure Functions | Quartz.NET |
|---|---|---|---|
| Every 5 minutes, starting at minute 2 | 2-59/5 * * * * | 0 2-59/5 * * * * | 0 2-59/5 * * * ? |
| Every 5 minutes, 09:00 to 17:59, Monday to Friday | */5 9-17 * * MON-FRI | 0 */5 9-17 * * MON-FRI | 0 */5 9-17 ? * MON-FRI |
C# code
Hangfire
// Hangfire: recurring jobs use Cronos. Times are UTC unless you set a time zone.
RecurringJob.AddOrUpdate<ReportJob>(
"daily-report",
job => job.RunAsync(),
"*/5 * * * *",
new RecurringJobOptions { TimeZone = TimeZoneInfo.Utc });
// Cronos on its own
var schedule = CronExpression.Parse("*/5 * * * *");
DateTime? next = schedule.GetNextOccurrence(DateTime.UtcNow);
Azure Functions
// Azure Functions (isolated worker): six fields, seconds first. Times are UTC
// unless WEBSITE_TIME_ZONE is set on the app.
[Function("DailyReport")]
public void Run([TimerTrigger("0 */5 * * * *")] TimerInfo timer)
{
}
// NCrontab on its own
var schedule = CrontabSchedule.Parse("*/5 * * * *");
DateTime next = schedule.GetNextOccurrence(DateTime.UtcNow);
Quartz.NET
// Quartz.NET with Microsoft.Extensions.DependencyInjection
services.AddQuartz(q =>
{
var jobKey = new JobKey("daily-report");
q.AddJob<ReportJob>(opts => opts.WithIdentity(jobKey));
q.AddTrigger(t => t
.ForJob(jobKey)
.WithIdentity("daily-report-trigger")
.WithCronSchedule("0 */5 * * * ?", x => x.InTimeZone(TimeZoneInfo.Utc)));
});
Common mistakes
Day numbers that mean different days in Quartz.NET, ranges that wrap in Azure Functions and the time zone each library assumes catch people with every schedule, not only this one. They are listed once, with fixes, on the cron expression builder.
When a run takes longer than the interval
Hangfire does not wait: it queues a new background job at every occurrence, even one still in progress, unless the job method carries [DisableConcurrentExecution]. Quartz.NET behaves the same way unless the job class has [DisallowConcurrentExecution]. An Azure Functions timer trigger is the exception; it skips the next fire while an invocation is still running, even across scaled-out instances.
FAQ
What is the cron expression for every 5 minutes?
*/5 * * * * in Linux crontab, Hangfire (Cronos) and NCrontab; 0 */5 * * * * in an Azure Functions timer trigger, which has a seconds field; 0 */5 * * * ? in Quartz.NET.
Does every 5 minutes count from when my app starts?
No. Cron follows the clock: */5 * * * * runs at fixed times (every 5 minutes), whenever the app was started or the job registered.
Is there a Hangfire shortcut for it?
Yes: Cron.MinuteInterval(5) returns "*/5 * * * *" in Hangfire 1.8.
Other common schedules
- Cron every minute
* * * * * - Cron every 15 minutes
*/15 * * * * - Cron every hour
0 * * * * - Cron expression builder for .NET (any expression, in all three libraries)