Loading

Extensions

Out-of-process custom code with resource limits, an outbound allowlist and a circuit breaker — the supported way to add server-side logic.

Extensions

An extension is a small piece of custom code that the platform runs at a defined point, such as when a field's value is drawn or when a workflow reaches a particular step. Every change is kept as a version, checked automatically, approved and only then put live, so custom logic can be added without editing the platform's own files.

Where to find it

Architect Panel → Automation:

  • Extensions — approve a version, put it live, roll it back, switch it off, and see its runs

Architect Panel → Layout & Pages:

  • App Code — the in-browser editor where extension code is written

Who does what

Writing extension code needs a developer. Running extensions safely does not. An architect, without writing code, can approve a version, put it live, roll back, disable it, clear its circuit breaker and read its run history, all from the Extensions screen. Any administrator can open App Code and write or check code, but only an architect can approve or put a version live.

Hooks: where an extension can run

Each extension is attached to one hook. The Hooks card at the bottom of the Extensions screen lists every hook with what it binds to, its time budget and what it is allowed to do. Two hooks are called by the platform today:

  • field.render: draws one chosen field on a record's form in place of the standard control. If the extension fails or is not live, the standard control is drawn as usual.
  • workflow.node: runs as an Extension step in a workflow built in the Workflow Builder. See Workflow Builder.

The other hooks in the list (record validation and saving, pages, endpoints, tasks) are defined but not yet called anywhere, so an extension written for them never runs. Some hooks also need a separate extension runner; where a system has none, the Hooks card says "no runner - refused on this install".

Binding: what it runs for

An extension runs only for the thing it is bound to. The detail panel shows this as Bound to. App Code does not set the binding, so after creating an extension an architect sets it on the extension's record in the Extensions datastore (Data → Datastores): Bound Datastore and Bound Field for a field, or Bound Key for a workflow step, matching the key the step names.

Statuses

  • draft: being written. gated: the latest version passed the code checker.
  • dryrun: being tested. live: running. Only live extensions ever run.
  • disabled: switched off by a person. quarantined: switched off automatically by the circuit breaker, or because the code checker was updated. See Limits and the Circuit Breaker.

Reading the Extensions screen

  1. The Installed list shows each extension's Name, Key, Hook, Status, Live and Draft versions and Breaker. "no such hook - this can never fire" means it names a hook that does not exist.
  2. Click Open for the detail: hook, Bound to, limits, the status buttons, the Circuit breaker card, Versions and Recent runs.
  3. A banner "Nothing published here can run." means no extension is live.

What goes wrong and how to tell

  • A live extension never seems to run: its hook is one the platform does not call yet, or its binding is empty or wrong. Check Hook and Bound to.
  • A workflow stops with "No live extension is registered for the workflow step": no live extension has a Bound Key matching that step. Bind one and put it live.
  • Status has changed to quarantined: the circuit breaker switched it off. Read the reason on the detail panel.

Worked example

A developer writes an extension in App Code, on the hook field.render, that shows a contract's end date on the contract form together with its remaining term, such as "4 months left". The architect sets its Bound Datastore and Bound Field to the contracts datastore's end-date field, opens it on the Extensions screen, approves the version and clicks Put live. Contract forms now show the remaining term beside the date. When a later version misbehaves, the architect uses Roll back to this on the previous version from the Versions card.

Recommendations

  • Use an extension only when configuration cannot do the job.
  • Check the hook is one the platform calls before commissioning code for it.
  • Set the binding before putting a version live.
  • Keep approving and writing with different people, even though the screen does not enforce it.

Limits and the Circuit Breaker

Every extension runs within fixed limits, and a circuit breaker switches off one that keeps failing. This article sets out the limits, what trips the breaker, how to tell that it has, and how to bring an extension back once it is fixed.

Where to find it

Architect Panel → Automation:

  • Extensions — open an extension for its Limits, Circuit breaker card and Recent runs

The limits

  • Time: each hook has a time budget, shown on the Hooks card (for example 250 ms to draw a field). The extension's own Timeout (ms), 2,000 ms unless changed, can only shorten that budget, never lengthen it. A run that overruns ends with "the extension ran longer than it is allowed to".
  • Memory: the extension's Memory Limit (MB), 64 MB unless changed. A run that exceeds it ends with "the extension used more memory than it is allowed to".
  • Data: one query returns at most 1,000 records.
  • Nesting: an extension that causes another to run can go at most three levels deep.
  • Code size: the code checker refuses code over 64 KB or that is too complex, so very large extensions must be split.

The detail panel also shows Outbound hosts and an e-mails-per-run figure. Extensions cannot currently make web requests or send e-mail at all, so those values are recorded but have no effect.

The limits are not a sandbox. Code that runs inside the platform shares the request it runs in: a call that blocks cannot always be interrupted, and a fatal error affects the page being drawn before the breaker can act.

What trips the circuit breaker

  • Five failures in a row, or
  • Twenty or more failures within five minutes, when more than half of that window's runs failed, or
  • A single crash of the page the extension was drawing.

When it trips, the extension's status becomes quarantined and it stops running at once. The reason is recorded in plain words ("it failed 5 times in a row", "it crashed the page it was drawing") and the Error Log gets an entry starting "Extension" followed by its number and "was turned off automatically". An extension is also quarantined, with the reason "the code checker has been updated, so this needs checking again", after a platform update changes the code checker.

Bringing an extension back

  1. Open the extension and read the Circuit breaker card (State shows "TRIPPED at" and the time) and the Recent runs table (When, Hook, Outcome, Duration, Peak memory, Message).
  2. Have the cause fixed in App Code, which saves a new version, then approve that version.
  3. Click Put live on the fixed version. Putting a version live clears the breaker.

Clear the breaker on its own resets the counters ("Circuit breaker cleared.") but leaves the status quarantined, so the extension stays off until somebody puts a version live. Nothing re-enables a quarantined extension automatically.

Reading the run history

Recent runs lists the latest 50 records. Every failure is recorded, but only about one successful run in fifty, to keep the table small. So a short list with no successes does not mean the extension is not running; and the warning that live extensions "none has ever run" can appear for an extension that is in fact running correctly.

What goes wrong and how to tell

  • Breaker column says "tripped": quarantined by the breaker. Follow the steps above.
  • Quarantined but Breaker shows "-": switched off after a crash or a checker update. Read the reason on the detail panel.
  • "no runner is configured for this cell" or "the runner could not be reached" in Recent runs: the hook needs the separate extension runner, which this system lacks or cannot reach. These failures count towards the breaker.

Worked example

An extension that formats a contract field starts failing after a field is renamed. After five failures in a row it is quarantined, the form falls back to the standard control for that field, and the Error Log records why. The architect sees "it failed 5 times in a row (last: error)" on the Extensions screen, asks the developer to update the field name, approves the new version and clicks Put live. The breaker clears and the formatted value returns.

Recommendations

  • Check the Extensions screen after any platform update for quarantined items.
  • Fix, then Put live; clearing the breaker alone does nothing visible.
  • Keep extensions small and fast, well inside their hook's budget.
  • Do not commission extensions that call outside services; they cannot today.

Versions and Rollout

Extension code is never edited in place. Every save creates a new version, and the version that runs only changes when an architect deliberately puts another one live. That makes it safe to work on a fix while the current version keeps running, and quick to go back if a new version misbehaves.

Where to find it

Architect Panel → Automation:

  • Extensions — the Versions card, status buttons and Recent runs for each extension

Architect Panel → Layout & Pages:

  • App Code — where new versions are written and checked

How a version moves to live

  1. Saved. A developer saves code in App Code. Saving creates a new version but never changes what is running.
  2. Checked. Each saved version is run through the code checker. The Gate column on the Versions card shows whether it passed. A version that failed is kept, but cannot be approved.
  3. Approved. An architect clicks Approve on the version ("Approved.").
  4. Live. The architect clicks Put live on that version and confirms "Put this version live? It will start running immediately." The message reads "Published v" and the version number. Putting a version live also clears the circuit breaker.

In App Code, an architect's Publish button does the approve and put-live steps together. The Versions card lists Version, Gate, Origin, Author and Approved for each one, so you can see who wrote what and whether it was checked.

Rolling back

To go back, click Roll back to this on an earlier version. It is subject to the same rules as any other version going live: it must have passed the current code checker and been approved. The message reads "Rolled back to v" and the version number. Nothing is lost; the later versions stay in the list.

The status buttons

  • Put live: runs the current published version. Refused if no version has been published yet ("There is no published version to run").
  • Disable: stops it immediately ("Disable this extension? It stops running immediately.").
  • Back to draft: takes it out of service while it is reworked.
  • Dry-run mode: marks it as under test. Despite the name, an extension in this status does not run on real events; only live extensions run. Test a version with Dry run in App Code instead.
  • Remove: deletes the extension but keeps its version history ("Removed. Its version history is kept.").

Testing before going live

App Code's Dry run runs the code once without writing anything and without sending anything, and shows the result. It runs with no record supplied, so it proves the code runs, not that it handles every real record. After putting a version live, watch Recent runs for failures; every failure is recorded there.

What goes wrong and how to tell

  • "This version has not passed the code checker, so it cannot be approved.": have the developer fix the findings and save again.
  • "This version was checked by an older version of the code checker.": after a platform update, save the version again in App Code to re-check it, then approve.
  • "This version has not been approved yet.": approve before putting it live.
  • The same person wrote and approved a version: the screen does not prevent this. If you want a second pair of eyes, make it your own rule.

Worked example

Version 4 of an extension is live. A developer saves version 5 with a change to the wording it draws; the Gate column shows it passed. The architect reads the code with the developer, clicks Approve, then Put live. Ten minutes later Recent runs shows errors on records with an empty date. The architect clicks Roll back to this on version 4, the errors stop, and the developer saves version 6 with the empty case handled.

Recommendations

  • Approve someone else's code, not your own, as a matter of practice.
  • Keep the previous version approved so a rollback is one click.
  • Watch Recent runs after every change going live.
  • Use Disable, not Dry-run mode, when you simply want it off.