Docs Decisions
0031 · A step can run later: the same automation, at a time its run chose, given what it asked to be handed back
Status: Accepted · 2026-11-02. It extends the next steps of 0030, which run as soon as a call is answered, to steps that run at a time a script chooses. The sandbox (0007) does not change.
Context
An automation now runs on an event, on a schedule, on a request from another app (0027), or on a call's answer (0030). Each runs now. Many flows have a step that should run later, relative to something that happened:
- A sign-up arrives: welcome them now, and check in three days whether they made their first page.
- An invoice is sent: if it isn't paid in 7 days, remind them; in 14, tell the account owner.
- A ticket is opened: if nobody has answered in 2 hours, tell the support lead.
- An API says to try in an hour, or a report should wait until a sync it started is done.
What exists can't do it well:
- A schedule runs at fixed times, not "three days after each sign-up".
- A frequent schedule and the state (0029) can fake it. The script keeps a list of what is due and a cron checks it every few minutes. That is hundreds of runs a day doing nothing, a list that hits 64 KB, and code that every such script writes again.
n8n's answer is a Wait node holding a running workflow. Here, a step is a run, and a run is 100 ms, so the waiting is the host's.
Decision
actions.later: run this automation again, at a time
// A sign-up: welcome now, and check on them in three days.
actions.email(form.email, 'Welcome', '…')
actions.later('3d', { step: 'check-in', email: form.email })
// Three days on:
if (event.type === 'later' && event.then.step === 'check-in') { … }
- When: a duration from the run,
'30m','2h'or'3d', or a time that is still to come, such as'2026-11-12T09:00:00+04:00'. At least a minute ahead, at most 90 days. Scripts have noDate, so a duration is counted from the run'sevent.at. then: any JSON, at most 16 KB, handed back as it was given, as a call's is (0030).- The step is told
event.type'later',event.then,event.step, andevent.due, the time it was asked for. It runs within a minute of that time, as the same automation and owner, with its current script and state. Like any run, it can call, remember, and ask for later again. - It counts as a step of its chain, as a call's answer does: a chain runs at most 10 steps in all (0030). "Remind every day until it's paid" belongs on a schedule.
One waiting step per key
actions.later(when, then, { key }) names a waiting step. Asking for later again with the same key
replaces the one waiting:
- "Remind them in 2 hours unless they answer" asks again on every answer, and only the last reminder stays.
- A step waiting for something that has happened is replaced, or checks when it runs and does nothing.
Without a key, every later waits.
What is kept, and who sees it
- Its owner sees what waits, on the automation's page under Waiting: when each is due, its
key, its
then, and the run that asked for it. They cancel one there, or all, and over MCP withget_automationandupdate_automation. Management never sees them, as it never sees a script. - At most 1,000 waiting per automation, and 20 asked for a run, within its 50 actions. A later past either is refused, saying so.
- The step's run record keeps its
then, and the run that asked for it, as a call's next step keeps its answer (0030). - A dry run and a preview ask for nothing. They show each later with the time it would run.
Try it later… on the automation's page, and
run_automationwithlaterandthen, run a step now, as if its time had come.
When it can't run
- A step due while its automation is switched off is dropped, and the Waiting list says so, as a call's next step is (0030). Switched on again, the steps not yet due still wait.
- Deleting the automation deletes what waits. Handing it to someone when its owner leaves hands its waiting steps over too, but they arrive switched off, as the automation does, so they are dropped as they come due unless it is switched on.
Consequences
- Delays relative to an event are one line, not a schedule, a list in the state, and a check every few minutes.
- Automations run when nothing visible has just happened. The Waiting list says what will run and when, and each such run's record says which run asked for it.
- Up to 1,000 waiting per automation. The scheduler finds them as it finds due schedules, in Postgres, so a restart loses none.
- Switching an automation off drops what comes due. That is the price of "off means off". The page says so before switching off one that has steps waiting.
Alternatives rejected
- A Wait in the script,
sleep('3d'): a run is 100 ms and keeps nothing in memory between runs. - A schedule per item: a cron for each sign-up is an automation per sign-up.
- The state and a frequent schedule, as today: many empty runs, a list against the 64 KB limit, and the same code in every script.
- Keeping steps due while the automation is off, to run when it is switched on: a reminder for last week would arrive late, and "off" would no longer mean nothing happens.
- Waiting for a person, "until someone approves": that is waiting on an event, which an event
automation already is. A page tagged
approvedstarts it, with the state saying what was waiting.
Settled when it was accepted
Tornike accepted it as proposed on 2026-11-02, settling:
- The shape:
actions.later(when, then, { key }), andevent.type'later'. - The limits: at least a minute, at most 90 days ahead; 1,000 waiting per automation, 20 asked for a run; within the chain's 10 steps.
- A step due while its automation is off is dropped, and the page says so.
- Asking again with a key replaces the step waiting under it.
Still open
- Waiting on a person in a step's own shape, if "an event automation and the state" proves awkward in practice.
- A run at a time of day in the person's own time zone, such as "9:00 the next working day", rather than a duration or a fixed time.
Building it
- Later:
actions.laterand the steps waiting, with their keys and limits;- the scheduler running them as they come due;
event.type'later', withevent.then,event.stepandevent.due;- dropping a step that comes due while its automation is off;
- the Waiting list and cancelling, on the page and over MCP;
- trying a later step now, and the contract.
- Docs: automations.md, and the
set-up-an-automationskill, with the sign-up check-in as its example.