Where Your Code Runs
You can write JavaScript in several places. They share one core set of names, and a few places add their own. Use this page to see what you can use where.
The basics (every place)
- Your code always runs as an
asyncfunction. Useawaitanywhere, with no setup.await httpClient.get(...)just works. returnsends a value on. Without it the result is empty.inputis the previous block's output. It is local to the code, so it never leaks into variables.- A name you assign without
const,letorvarbecomes a request variable that later blocks can read. See Scripting Context. - Libraries are not built in. Only
jwtis. Install anything else (Day.js, Zod, Lodash...) in Project Settings > npm Packages andimportit. See Imports & Libraries.
All the places
| Where | You write code in | Adds |
|---|---|---|
| Route (HTTP request) | JS Runner, Transformer, js: fields and conditions on any block | The core names |
| Workflow (started by a trigger, a schedule, Trigger Workflow or the Run button) | The same blocks and fields | The core names, with different values |
| Custom block | The same blocks, inside the block's own canvas | params, the settings filled in where the block is used. See Custom Blocks |
| Middleware custom block | The same blocks, inside the block's own canvas | The core names, but no params: a middleware block takes no settings. After the route, input starts as { httpCode, body }, and getResponseBody() / getResponseStatus() return the reply. See Middlewares |
| DB Native block | Its JS field | dbQuery(query, params?) on PostgreSQL and MySQL, db and ObjectId on MongoDB. See DB Native |
| KV Raw Connection block | Its JS field | kv, the raw client. See KV Raw Connection |
| Test-only custom block (setup and teardown) | The block's canvas | testsuite. See Setup and Teardown |
| Request validation ("Use JavaScript" on a field) | The field's code box | input is the field's value. Return a truthy value to pass, or throw new ValidationError(...). See Routing. No import here. |
| Test hooks and checks | The Hooks and Checks tabs of a suite | t and fluxify, not the names on this page. See Hooks and Checks |
| Workflow test input script | The suite's input tab | Works like a JS block. See Testing Workflows |
Core names
Available in every block and js: field of a route, workflow and custom block. The full list with types is the JavaScript API Reference.
| Name | What it is |
|---|---|
input | The previous block's output |
outputs | Outputs saved with Save output to variable, by name. It does not exist until a block has saved one, so use outputs?.name if unsure |
trigger | What started this run |
getRequestBody(), getQueryParam(k), getRouteParam(k), getHeader(k), getCookie(k) | Read the request |
httpRequestMethod, httpRequestRoute | The method and path of the request |
setHeader(k, v), setCookie(name, options) | Add to the response |
getResponseBody(), getResponseStatus() | The reply, in an after middleware. null anywhere else |
getConfig(key) | A value from App Config |
httpClient | Call other services |
logger | logInfo, logWarn, logError |
jwt | sign, verify, decode |
ValidationError | An error class for request validators |
Routes and workflows
A workflow has no HTTP request, so the request names exist but are empty:
| Name | In a route | In a workflow |
|---|---|---|
getRequestBody() | The request body | The payload the run was given (the same value as input at the start) |
getQueryParam, getRouteParam, getHeader, getCookie | The request values, "" when missing (undefined for getQueryParam) | Always "" (undefined for getQueryParam) |
httpRequestMethod | "GET", "POST"... | "" |
httpRequestRoute | The request path | An internal id, not a URL |
setHeader, setCookie | Add to the response | Do nothing, there is no response |
trigger | kind: "route", source: "http", no data | kind: "trigger", with the events in trigger.data |
A route called with the header x-fluxify-reply: async runs in the background and answers 202 straight away. setHeader and setCookie do nothing there either.
trigger
typescript
trigger: {
kind: "route" | "job" | "workflow" | "cron" | "trigger";
source: string; // "http", "internal", "schedule", "kafka", "nats"...
reply: "sync" | "async";
id?: string;
data: { data: any; meta: { id?: string; receivedAt?: string; source?: string } }[];
meta: { batchId: string; size: number; attempt?: number; /* ... */ };
connection?: { raw; commit(); moveToDLQ(error?); lag() }; // queue triggers only
}- Use
trigger.sourceto tell runs apart. A schedule iskind: "trigger"withsource: "schedule". The Trigger Workflow block and the Run button aresource: "internal". trigger.datais always a list, even for one event.inputis the bare payload when there is exactly one event, and a list of payloads when there are more.kind: "job"is a custom block that was queued to run later. The values"workflow"and"cron"are reserved and not used yet.- Full details, batching and the queue controls are in Triggers.
Time limits
Your code has no separate time limit. The whole run has one:
- Routes: the route's timeout setting (30 seconds by default). It is enforced by the experimental worker watchdog, which you turn on with
experimental.workerTimeouts.enabled. - Workflows: the workflow's own timeout setting (300 seconds by default).
Keep waits short and give outgoing calls their own timeout. See Execution Limits & Safety.
