Aquargin Way / Build Functions / Module 06

Triggers, Jobs & Pages

You can already build a function. Now learn the other three ways one can run: automatically on save, on a nightly schedule, and interactively from a button — each with its own rules, all wired the right way.

6 units ~26 min Earn the Automator stamp
Unit 1 of 6

Triggers: run on save

A trigger function runs automatically whenever records on an object are inserted, updated or deleted — no button, no schedule, no person clicking anything. The save itself is the trigger.

This is how you keep data honest without anyone thinking about it: stamp a field on insert, roll a total up to a parent on update, archive children on delete. Wire it once and it just happens, every time, forever.

The one fact that shapes every trigger

Here's the rule that catches everyone the first time. When a trigger fires, its start node does not hand you the one record that changed — it hands you the list of all affected records. Save one Lead and you get a list of one; a bulk update of fifty Leads fires the trigger once with a list of fifty.

So a trigger function always loops over that list — exactly the loop you met in Modules 04 and 05. You read the list, you iterate, and you write back after the loop:

start
records: list
loop
each record →
assignment
set a field
update
save the list

Notice the shape: the loop walks each record and an assignment sets values on it, but the update sits after the loop and writes the whole list at once. That's Module 05's bulkify rule, and it is not optional in a trigger — a trigger that ran on fifty records and put a write inside the loop would do fifty separate database calls.

The start node passes the LIST

A trigger always receives the list of affected records — even when only one record changed. Loop over it. Never assume a single record. Build it to handle fifty and the case of one takes care of itself.

For developers — the start parameter is a list of the object

When you declare a trigger function, the input parameter the start node passes is the list of that object, not a single record. The parameter is marked as a list (isList: true) and typed to the object's API name:

trigger input
// the start node hands you a LIST — always
[{ name: 'records', datatype: 'object',
   objectApi: '<object-api>', isList: true }]

The variable name is yours to choose (records is conventional). Whatever you call it, that exact name has to be matched when you wire the trigger — Unit 3 shows the wiring shape.

Unit 2 of 6

Before vs After

Triggers fire at one of two moments: before the record is saved, or after. They look almost identical on the board, but they behave very differently — and choosing the wrong one is the single most common trigger mistake.

The difference comes down to two questions: does an assignment to the triggering record persist on its own, and what does a notification do? Here is the whole story, side by side.

BEFORE — onBeforeSave

The save hasn't happened yet, so you're editing the record on its way in. An assignment to the triggering record auto-persists — you do not add an update node; the values you set ride along into the save. A notification here prevents the save — which makes Before the natural home for validation ("block this save and tell the user why").

AFTER — onAfterSave

The record is already written. An assignment to the triggering record does not persist — to make a change stick you must add an update node. A notification here only shows a message; it cannot stop the save (it already happened). After is where you do side-effects: roll up a total, create a follow-up task, fire an email.

One thing is the same in both: writing to other objects is always allowed. Updating a parent record, creating a child, deleting a related row — fine in Before, fine in After. The Before-vs-After rules above are specifically about the record that triggered the function.

The recursion trap in After triggers

If an After trigger on an object updates that same object, that update can fire the trigger again, whose update fires it again… a loop that never settles. The fix is a condition: before you write, check whether the work is already done, and skip the update if it is.

loop
each record
condition
already stamped?
assignment
set it (only if not)
update
save once
Guard self-updates in After triggers

An After trigger that updates its own object can re-fire itself endlessly. Always gate the write with a condition — "is the field already set to what I'd set it to?" — so the second pass finds nothing to do and stops. Before triggers don't have this problem: they change the record in flight, with no second save.

Unit 3 of 6

Wiring the trigger

Building the function is only half the job. A trigger function does nothing until it is connected to record events through workflow wiring — and the wiring has a few exact rules that, if you miss them, fail silently.

The wiring tells the platform three things: which function to run, what to pass it, and which events to listen for. It looks like this:

trigger wiring
{
  function: 'flag_overdue__fx',        // note the __fx suffix
  functionParams: [
    { name: 'records',          // MUST match the function's input param
      value: 'list-new',
      type: 'list',            // MUST be 'list', never 'object'
      useContext: true }
  ],
  triggers: [
    { label: 'On Create', name: 'onAfterInsert', enabled: true },
    { label: 'On Update', name: 'onAfterUpdate', enabled: true }
  ]
}

Read it top to bottom. The function is the one you built (with its __fx suffix). functionParams is the bridge that hands the event's records into your input parameter. And triggers is the list of events to fire on — each with a human label, an event name, and an enabled flag so you can turn individual events on and off.

The four wiring rules — get all four right

functionParams type must be 'list'not 'object'.
② The param name must match the function's input parameter exactly (here, records).
③ The function name must include the __fx suffix.
Compilation is activation — there is no separate "activate" step. Compile the workflow and it is live.

For developers — why these four, and how they fail

Each rule maps to a real failure mode:

  • type 'object' instead of 'list' — the event hands over a collection; declaring it as a single object means the function receives a malformed value and your loop has nothing to iterate.
  • name mismatchfunctionParams[].name is bound by name to the function's declared input. If the function expects records and the wiring passes recordList, the input arrives empty; the function runs and quietly does nothing.
  • missing __fx — the suffix is how the platform resolves the compiled trigger entry point. Without it the lookup misses.
  • expecting an activate step — there isn't one. The compile is the activation; if it compiled, it's running.

value: 'list-new' with useContext: true tells the wiring to pull the list of affected records from the event context and hand it in as your parameter.

Unit 4 of 6

Scheduled jobs

Some work isn't triggered by a save at all — it just needs to happen on a schedule. Nightly cleanups, hourly reminders, end-of-day rollups: that's a scheduled job, a function that runs on a cron timer with nobody watching.

Because no user and no record kicked it off, the scheduled_job context is the most self-contained of all. It takes no inputs and returns no outputs — there's nowhere for data to come from or go to. And critically, it may not contain page nodes: there is no user session, no screen, nobody to answer a prompt.

It's almost always a batch

A scheduled job's whole job is usually "find the records that need attention and act on all of them." That is exactly Module 05's batch shape — query the set up front, loop to decide, write back in bulk after the loop:

start
no inputs
query
find the set
loop
decide per record
update
bulk save

One query before the loop, one bulk update after it — never a write inside. A nightly job can touch thousands of records, so bulkify isn't a nicety here; it's the difference between finishing in seconds and timing out.

A worked example

"Every night at 2 a.m., flag invoices overdue by 30 days." The job queries all invoices whose due date is more than 30 days past and whose status isn't already Overdue, loops to set status = "Overdue" on each, then does one bulk update after the loop. No button, no person — the cron schedule runs it while everyone sleeps.

Unit 5 of 6

Interactive functions (pages)

Sometimes a button action needs to ask the user something partway through — "which warehouse?", "are you sure?", "enter a reason." When that happens, the function itself pauses and shows a screen by adding a page node.

The instinct of someone coming from other tools is to build a separate custom page that collects the input and then calls a function. On this platform, don't. The page lives inside the function as a node, and the flow continues right after the user answers:

start
recordId
page
ask the user
condition
on their answer
update
save the result

The page node collects input, a condition branches on what they chose, and the rest of the flow finishes the job — all in one function, one continuous flow.

The Zero Rule — buttons are functions

A button action is always a function with call context layout_buttonnever a standalone custom page that calls back to a function. If the action needs user input mid-flow, add a page node inside the function. One function, start to finish.

Only interactive contexts can show a page

Page nodes need a user session — a person on the other end of the screen. So they belong only to interactive contexts (a button, a page form). Triggers and scheduled jobs have no UI session and therefore cannot contain page nodes. A trigger runs on a save; a job runs on a timer; there's no one there to answer.

For developers — the page node and the five contexts

The page node is one of the real node types — alongside assignment, query, loop, condition, create, update, delete, notification, functionCall, alert, job and note. (There is, as ever, no node called "DML" — writes are create / update / delete.)

Where a page node may appear maps straight onto the five call contexts:

  • layout_button — interactive: page nodes allowed.
  • page_onload / page_formButton — interactive: allowed.
  • trigger — runs on save, no session: not allowed.
  • scheduled_job — runs on cron, no session: not allowed.
Unit 6 of 6

The whole trail

That's it — you've reached the end of the trail. Look back at how far you've come: you can now build all four ways a function runs, the right way, with the rules that keep them fast and correct.

The journey, module by module

01 · Foundations
what a function is + the five call contexts
02 · First build
receive → read → change → write
03 · Data
querying, fields, variables
04 · Logic
conditions & loops
05 · Writing & bulkify
create / update / delete, out of loops
06 · Automation
triggers, jobs & pages

The four ways you can now make a function run

  • A button — context layout_button. A user clicks; the function acts on a record (Module 02, and the Zero Rule throughout).
  • An automation — context trigger. A save fires it with the list of affected records; you loop and write after (Unit 1).
  • A scheduled job — context scheduled_job. A cron timer runs a no-input batch; query before, bulk write after (Unit 4).
  • An interactive flow — a function with a page node that asks the user mid-flow, then carries on (Unit 5).

Across all four, the same instincts carry you: declare your intent and call context first; read before you write; branch with conditions; loop over lists; and keep every query/create/update/delete out of your loops. That toolkit builds most of a platform.

Keep the Function Reference open in another tab as your companion — every standard function and formula, searchable, for when you need the exact name or signature. And the whole trail is always one click away from all modules if you want to revisit a unit.

You finished the trail 🎉

Button, trigger, scheduled job, interactive page-node flow — you can build them all. Pass the final checkpoint to claim your Automator stamp and complete Aquargin Way. Now go build something real.

Checkpoint

Earn the Automator stamp

Five questions to complete the trail.