Configure runtime and secrets

Set a function's timeout and memory, allow-list outbound hosts, add config keys, and store credentials in secret bundles.

5 min read

Set the runtime envelope your function executes in, open up the outbound network calls it needs, and give it credentials without putting them in your source. Everything here is per-function except secret bundles, which are shared across the tenant.

Before you begin

  • The function already exists. If not, start with Create and build a function.
  • You are an Admin working in the Global Organization.
  • Have the exact hostnames of any API your handler calls. Wildcards are not accepted.

Runtime limits

Open the function and use the Settings tab. The first card bounds a single invocation.

SettingRangeDefaultWhat it controls
Timeout (ms)50 – 20002000Wall-clock time your handler gets. Also the effective processing limit — a runaway loop is interrupted when the clock runs out.
Max memory pages1 – 6432Memory available to your handler, at 64 KiB per page. The default is 2 MiB and the ceiling is 4 MiB.

Leaving a field empty uses the service default. Because the default timeout is already the ceiling, the only useful direction to move it is down.

On a hook, a timeout is a refused signup — not a graceful degradation

A hook runs inside a real user's request, so a 2000 ms timeout can add two seconds to every signup the binding covers. Tightening it is tempting, but hooks fail closed: an expired handler is treated as a refusal, so a shorter timeout trades latency for lost customers.

Do the arithmetic before you change it. Your handler gets at most 2000 ms, and a single HTTP request inside it can take up to 1500 ms. Set the handler to 400 ms because your provider's median is 180 ms, and every slow response in the tail — a provider blip, a DNS hiccup, a TLS renegotiation — refuses a real signup.

Leave headroom for your dependency's slow tail, and catch its failures in code rather than letting them expire: a handler timeout cannot be caught, but an HTTP error can. See when your provider fails.

Beyond the timeout, two limits apply to every function and cannot be raised: a maximum of 20 SDK calls per invocation, and a 1500 ms timeout on each individual HTTP request.

Allowed hosts

The second card is the outbound network allow-list. This is the single most common reason a working handler fails in production.

  • A function with no allowed hosts is refused every outbound request. This is the default for a new function.
  • Entries are exact hostnames, matched case-insensitively — api.example.com. Wildcards, paths, ports, and raw IP addresses are all rejected.
  • Only http and https are permitted.
  • You can add up to 16 hosts. The card shows a live count.

Type a hostname and press Enter or select Add. Each host becomes a removable chip.

Private and internal addresses are always refused

Private network ranges, loopback, link-local addresses, and internal cluster hostnames are blocked even if you add them to the allow-list. The check is repeated after DNS resolution, so a public hostname that resolves to a private address is also refused. A blocked call raises an EGRESS_BLOCKED error in your handler.

Settings tab showing runtime limits, the allowed hosts allow-list and plugin config

Plugin config

The third card holds free-form key and value pairs that your handler reads at runtime with OmniLab.Config.get. Use it for things that differ between environments or organizations but are not sensitive — a template id, a feature toggle, a base URL.

Reading a config key
const templateId = OmniLab.Config.get("brevo_template_id");

You can store up to 32 keys, totalling 4 KB. Reading a key that is not set returns undefined. Rows with an empty key are discarded when you save.

Never put credentials in plugin config

Plugin config values are stored as plain configuration and are readable by anyone who can open the function. API keys, tokens, and passwords belong in a secret bundle.

Secret bundles

A secret bundle groups credentials under one key — for example a brevo bundle holding api_key. Bundles live at tenant level so several functions can share them, and values are write-only: once saved, they are never shown again.

Create a bundle

Scroll to the Secrets section below the function list on the Functions tab and select New secret.

FieldWhat to enter
KeyThe name you use in code. Lowercase letters, digits, and underscores, starting with a letter, up to 32 characters. Permanent.
Display nameA human-readable label, such as Brevo Production.
DescriptionOptional note about what the credentials are for.

Then add one secret per credential, with a key such as API_KEY and its value. Select Save secrets.

A tenant can hold 5 bundles, each with up to 32 secrets.

Secret bundle panel with a stored secret shown as a masked value

Bind a bundle to a function

On the function's Settings tab, use the Secret bundles card and select the bundles this function should be able to read. A function can bind up to 5 bundles.

Once bound, the card lists a ready-to-copy reference for every secret in the bundle. Read a value at runtime with its fully qualified name:

Reading a secret
const apiKey = OmniLab.Config.getSecret("brevo.api_key");

A function can only read secrets from the bundles bound to it. Reading a key that does not exist throws a NOT_FOUND error rather than returning empty, so a typo fails loudly.

Change or remove a secret

Reopen the bundle. Existing values show a masked placeholder — leave a row untouched to keep its value, type a new value to replace it, or use the row's toggle to mark it for removal. A bundle cannot be deleted while a function still references it.

Save your changes

Select Save settings. Runtime limits, allowed hosts, plugin config, and bundle bindings all take effect on the next invocation — none of them require a rebuild, because none of them change your compiled code.

If something's blocked

An HTTP call fails with EGRESS_BLOCKED. The hostname is not in the allow-list, is spelled differently from what you allow-listed, uses a scheme other than HTTP or HTTPS, or resolves to a private address.

Reading a secret throws NOT_FOUND. Check that the bundle is bound to this function on the Settings tab, and that the reference is bundle_key.secret_key — both halves matter.

A bundle you bound shows as unknown. The bundle was deleted after it was bound. Remove the stale reference and bind an existing bundle.

Writing a contact custom field is rejected. Keys beginning system. or feature. are reserved by the platform. Choose a different key.

A timeout value is refused. The field accepts 50 to 2000 milliseconds. Values above the ceiling are not accepted, because the ceiling exists to keep synchronous hooks off the critical path for longer than that.

On this page