n8n cron expressions have five fields: minute, hour, day-of-month, month, day-of-week. */15 * * * * fires every 15 minutes, 0 9 * * 1-5 fires weekdays at 9:00 AM, and n8n reads them in the workflow's timezone setting. Below: every common schedule as a copy-paste expression with the exact Schedule Trigger node settings \u2014 or build yours in the free n8n cron generator.
How Scheduling Works in n8n
n8n runs workflows on a schedule through the Schedule Trigger node (older docs and tutorials call it the Cron node \u2014 same thing, it was renamed). You drop it in as the first node, and instead of waiting for an app event or webhook, n8n starts the workflow whenever the schedule says so. Everything else in the flow is unchanged.
The node has one setting that matters most: Trigger Interval. It offers six modes, and each mode exposes different fields:
- Seconds / Minutes \u2014 a single “every N” field
- Hours \u2014 every N hours +
Trigger at Minute - Days \u2014 every N days +
Trigger at Hour+Trigger at Minute - Weeks \u2014 every N weeks +
Trigger on Weekdays+ hour + minute - Months \u2014 every N months +
Trigger at Day of Month+ hour + minute - Custom (Cron) \u2014 a free-text
Expressionfield
The interval modes cover most needs without any cron syntax. The Custom (Cron) mode exists for the schedules the UI can’t express: twice daily at odd hours, business-hours-only windows, specific months, or anything with ranges and lists. If you’re brand new to n8n itself, the n8n beginner’s guide covers the canvas basics first.
One n8n-specific rule worth knowing early: n8n evaluates the cron expression once, when you publish the workflow. Expressions with variables that only resolve at runtime don’t work \u2014 the schedule is fixed at publish time.
The Cron Expression Format in n8n
An n8n cron expression has five fields, separated by spaces. n8n also accepts an optional sixth field at the front for seconds \u2014 leave it off unless you genuinely need sub-minute schedules.
Expression above: */15 9 * * 1-5 \u2014 every 15 minutes between 9:00 and 9:45, Monday to Friday
Four characters do all the work: * (every value), , (list: 9,17), - (range: 1-5), and / (step: */15). Day of week counts 0–7, where both 0 and 7 mean Sunday and 1 means Monday. And one classic trap: when both day-of-month and day-of-week are restricted (neither is *), standard cron fires when either matches, not both. n8n follows that convention, so avoid restricting both unless you want the OR behavior.
Timezone: The #1 Reason a Cron Fires at the Wrong Hour
n8n interprets every field in a timezone, in this order: the workflow’s own timezone setting (three-dot menu on the workflow → Settings → Timezone), falling back to the instance timezone (GENERIC_TIMEZONE environment variable). A self-hosted instance without that variable defaults to America/New_York; n8n Cloud tries to detect your timezone when you sign up and falls back to GMT if detection fails. Neither default will match most people’s expectations.
“My 9 AM workflow runs at 9 AM… in New York.” That’s the self-hosted default talking. Set the timezone on the workflow, not just the instance, so duplicating or exporting the workflow keeps its schedule honest. After changing it, save and re-publish \u2014 the schedule is recalculated on publish.
Copy-Paste Examples for Every Common Schedule
Each example below gives the expression, the equivalent settings in the Schedule Trigger UI where one exists, and exactly when it fires. Prefer the UI equivalent when it exists \u2014 it reads plainly to whoever inherits the workflow. For anything the UI can’t express, use Custom (Cron) mode.
Every 15 minutes
High-frequency pollingWhen it fires: 12:00, 12:15, 12:30, 12:45 \u2014 every day, aligned to clock quarter-hours.
Schedule node UI: Trigger Interval Minutes · Minutes Between Triggers 15
Hourly at :30
Off-the-hour runsWhen it fires: every hour at 30 minutes past \u2014 9:30, 10:30, 11:30…
Schedule node UI: Trigger Interval Hours · Hours Between Triggers 1 · Trigger at Minute 30
Every 6 hours
Four runs a dayWhen it fires: 00:00, 06:00, 12:00, 18:00. The step counts from midnight, not from when you published.
Schedule node UI: Trigger Interval Hours · Hours Between Triggers 6 · Trigger at Minute 0
Daily at 9:00 AM
The daily workhorseWhen it fires: 9:00 AM every day, in the workflow’s timezone.
Schedule node UI: Trigger Interval Days · Days Between Triggers 1 · Trigger at Hour 9am · Trigger at Minute 0
Twice daily, 9 AM and 5 PM
No UI equivalent \u2014 cron neededWhen it fires: 9:00 AM and 5:00 PM every day. The hours field takes a list, which the interval UI can’t express.
Schedule node UI: Trigger Interval Custom (Cron) · Expression 0 9,17 * * * \u2014 or duplicate the trigger with two Days-interval rules.
Weekdays only, 9:00 AM
Mon–FriWhen it fires: 9:00 AM Monday through Friday. Never weekends, whatever your calendar says.
Schedule node UI: Trigger Interval Weeks · Weeks Between Triggers 1 · Trigger on Weekdays Mon, Tue, Wed, Thu, Fri · Trigger at Hour 9am
Business hours only, every hour
No UI equivalent \u2014 cron neededWhen it fires: on the hour from 9:00 AM to 5:00 PM, Monday to Friday. A range in the hours field times a list in the day field.
Schedule node UI: Trigger Interval Custom (Cron) · Expression 0 9-17 * * 1-5
Every Monday at 8:00 AM
Weekly report energyWhen it fires: 8:00 AM every Monday. For Tuesday use 2, Saturday 6, Sunday 0 (or 7).
Schedule node UI: Trigger Interval Weeks · Weeks Between Triggers 1 · Trigger on Weekdays Monday · Trigger at Hour 8am
First day of the month, midnight
Monthly billing / wrap-upWhen it fires: 00:00 on the 1st of every month. For the 15th, change the third field to 15.
Schedule node UI: Trigger Interval Months · Months Between Triggers 1 · Trigger at Day of Month 1 · Trigger at Hour 12am · Trigger at Minute 0
Last day of the month
The honest workaroundWhen it fires: midnight on the 28th, 29th, 30th and 31st \u2014 so pair it with an IF node that only continues when tomorrow is the 1st (expression: {{ $now.plus({ days: 1 }).day }} equals 1). n8n’s cron doesn’t support the L last-day syntax; this is the pattern the community and n8n staff recommend.
Schedule node UI: Trigger Interval Custom (Cron) · Expression 0 0 28-31 * * → then an IF node
Quarterly (Jan 1, Apr 1, Jul 1, Oct 1)
No UI equivalent \u2014 cron neededWhen it fires: midnight on the 1st of January, April, July and October. This exact pattern comes straight from n8n’s own documentation.
Schedule node UI: Trigger Interval Custom (Cron) · Expression 0 0 1 1,4,7,10 *. A “every 3 months” interval is anchored to when you publish, so if the exact months matter, use cron.
A specific date every year
AnnualWhen it fires: 9:00 AM every December 25th. Cron has no one-shot mode \u2014 it will fire again next year, so deactivate the workflow if you only want it once.
Schedule node UI: Trigger Interval Custom (Cron) · Expression 0 9 25 12 *
Bonus: every 30 seconds
Six-field formWhen it fires: twice a minute. That leading field is n8n’s optional seconds slot \u2014 the same schedule as the node’s Seconds interval at 30.
Schedule node UI: Trigger Interval Seconds · Seconds Between Triggers 30
Quick reference table
| Schedule | Expression | Schedule node UI equivalent |
|---|---|---|
| Every 5 minutes | */5 * * * * | Minutes · 5 |
| Every 15 minutes | */15 * * * * | Minutes · 15 |
| Hourly on the hour | 0 * * * * | Hours · 1 · at minute 0 |
| Every 6 hours | 0 */6 * * * | Hours · 6 · at minute 0 |
| Daily at 6:00 AM | 0 6 * * * | Days · 1 · 6am |
| Weekdays at 9:00 AM | 0 9 * * 1-5 | Weeks · 1 · Mon–Fri · 9am |
| Mondays at noon | 0 12 * * 1 | Weeks · 1 · Monday · 12pm |
| Every 3 days, midnight | 0 0 */3 * * | Days · 3 · 12am |
| Monthly on the 1st | 0 0 1 * * | Months · 1 · day 1 · 12am |
| Quarterly | 0 0 1 1,4,7,10 * | Custom (Cron) |
| Every 30 seconds | */30 * * * * * | Seconds · 30 |
One small print on the “every N days” row: in cron, */3 in the day-of-month field steps through the month (1st, 4th, 7th… and resets monthly). The node’s Days interval counts real elapsed days instead. For a true rolling “every 72 hours,” use the UI setting.
Interval or Cron? A 10-Second Decision
“Every N minutes / hours / days / weeks / months.” Use the interval modes \u2014 no syntax to break.
Lists, ranges, specific months, “9-to-5 weekdays only.” Use Custom (Cron).
Cron has no one-shot. Schedule it, then deactivate after it runs \u2014 or gate the flow with a date check.
Not Firing? Check These in Order
- 1. Published, not just saved. Unpublished workflows never trigger. Publish after every trigger change \u2014 the expression is re-read at publish time.
- 2. Workflow timezone. Workflow Settings → Timezone. This decides what “9” means. See the gotcha above.
- 3. No runtime variables. The expression is evaluated on publish;
{$json}-style values don’t exist there yet. - 4. Field count. Pasted a 6-field expression by accident? Everything shifts one slot left and the schedule means something else.
- 5. Executions actually happening. Check the workflow’s Executions list. If it’s empty at the right times, it’s the trigger; if it ran and failed, that’s a workflow problem \u2014 the n8n error handling guide covers alerting on exactly this.
Skip the Syntax: Free n8n Cron Generator
Pick a schedule in plain English, get the expression plus the exact Schedule Trigger settings and the next three run times in your timezone:
n8n Cron Expression Generator
Interval, time, days and timezone in \u2014 copy-paste cron expression, Schedule-node settings and the next three fire times out. Fully client-side.
Open the free generator →Automations Are One Piece. Build the Whole System.
A workflow that fires on time is table stakes. The compounding part is the system around it \u2014 what the workflow feeds, what it learns, and what you ship next. That’s what the programs here cover end to end.
Every program. One subscription.
AI SaaS Builder, AI Automations, AI Influencers, Digital Products \u2014 plus weekly live coaching, the private community and every future program. Four courses bought separately cost $702; All Access is $99/month.
Free Value, No Card Required
- Free Creator Starter Kit \u2014 the starting blocks for the automation-first approach
- Free Discord community \u2014 swap cron expressions and workflow patterns with other operators
- Telegram channel \u2014 short, regular drops on automation and AI
FAQ
Why doesn’t my n8n cron expression fire?
Check four things in order: (1) the workflow is published/active — saved-but-unpublished workflows never trigger; (2) the workflow timezone setting matches where you expect 9 AM to happen — self-hosted instances default to America/New_York and n8n Cloud falls back to GMT if detection fails; (3) the expression itself is valid — n8n evaluates it when you publish, so variables that only exist at runtime won’t work; (4) you’re checking the right window — 0 9 * * 1-5 will never run on a Saturday, no matter how many times you refresh.
What timezone does n8n use for cron expressions?
The workflow’s timezone if one is set (open the workflow, three-dot menu, Settings, Timezone), otherwise the instance timezone (GENERIC_TIMEZONE environment variable). A self-hosted instance without GENERIC_TIMEZONE defaults to America/New_York; n8n Cloud tries to detect your timezone and falls back to GMT. Set it at the workflow level so a moved or duplicated workflow keeps firing at the same local time.
How do I make n8n run every 15 minutes?
Use the cron expression */15 * * * * in a Schedule Trigger with the Custom (Cron) interval, or skip cron entirely: set Trigger Interval to Minutes and Minutes Between Triggers to 15. Both fire at 12:00, 12:15, 12:30 and 12:45 — the minute-based interval aligns to clock quarters rather than counting 15 minutes from activation.
Does n8n use 5-field or 6-field cron expressions?
Five fields by default: minute, hour, day-of-month, month, day-of-week. n8n also accepts an optional sixth field at the front for seconds — */30 * * * * * runs every 30 seconds. If you paste a 6-field expression and it behaves unexpectedly, count the fields: most "broken cron" cases are a seconds field that shifts everything left by one.
Cron expression or interval — which Schedule Trigger mode should I use?
Use the interval modes (Minutes, Hours, Days, Weeks, Months) whenever they express your schedule — they map to plain fields and are harder to get wrong. Switch to Custom (Cron) when you need list or range logic the UI can’t express: twice daily at 9 and 17 (0 9,17 * * *), business hours only (0 9-17 * * 1-5), or specific months (0 0 1 1,4,7,10 *).
Can an n8n cron expression run on the last day of the month?
No reliable L (last-day) syntax exists in n8n’s Schedule Trigger — it’s a long-standing feature request. The dependable pattern is 0 0 28-31 * * with an IF node right after the trigger that compares tomorrow’s date to the 1st (in an expression: tomorrow is the 1st means today is the last day) and only continues the flow when it matches.