Skip to main content
The Execute Code node runs Python when the other nodes can’t do what you need. Use it to reshape data, do calculations, loop over hundreds of records, create files, or call your connected apps (Gmail, Slack, Google Sheets and more) from code. Don’t write code? Click Generate with AI, describe the step in plain English, and the AI writes it for you. It knows what earlier nodes returned and which apps this node can call.

A one-minute tour: bind apps, write a call with the editor's help, fix a mistake, and ask AI for a change.

The Execute Code panel: step name and ID, the Integrations summary, the Python editor, and the list of integration functions

An Execute Code node that reads a Google Sheet and posts each qualified lead to Slack.

When to use

  • Reshaping data: rename fields, filter lists, merge results from two nodes
  • Calculations: totals, percentages, dates and business days
  • Text processing: find emails or phone numbers, clean up names, split text
  • Working through many records: read rows from one app and act on each in another, in one step
  • Keeping track between runs: remember where the last run stopped in a workflow variable
  • Creating files: CSV, Excel, charts or PDFs that later steps send or store
  • Your own rules: anything specific to your business
Not sure code is the right tool? Execute Code scenarios compares code with the other nodes and walks through common jobs step by step.

Using data from earlier nodes

The output of every earlier node is a Python value named after the node’s key. Read fields with square brackets:
Workflow variables work the same way: use the variable’s key as a Python name. They are copies. To change a variable for the rest of the run, use set_variable. Available Variables, under the editor, lists the outputs and variables you can use. Click one to insert it.
Available Variables panel with webhook_1 outputs and two workflow variables

Available Variables: earlier nodes' outputs in blue, workflow variables in purple. Click to insert.

Use node_key["field"], not node_key.field. The values are plain Python dictionaries and lists.
A step’s key is shown as the Step ID in the step panel (“Other steps use this ID to read this step’s output.”), and it changes when you rename the step. If your code uses a key that doesn’t exist, or a node that hasn’t run in this run, Python stops with NameError: name '…' is not defined. You can also write {{node_key.field}} anywhere in the code. It is replaced with the value as text, before the code runs, so it changes the code itself. That suits a short value like an ID. For anything else use the Python names above, which give you the real value.

Returning data

Send structured data to the next nodes with output_data(...):
Later nodes read it as {{execute_code_1.result}}, or deeper, like {{execute_code_1.result.count}}. After a test run, the variable picker in later nodes lists these fields too.
  • Anything you print() goes to the stdOut output, which is useful for debugging.
  • Without output_data(...), result holds the value of the last line, as text.
Anything written to the error stream fails the step, Python warnings included. If a library prints a warning, the node reports a failure even when the rest worked. Catch the errors you expect, and silence warnings you know about:

Creating files

Files the code saves under a plain file name are attached to the step’s files output:
To send or store the file, insert this step’s files output, for example {{execute_code_1.files[0]}}, into an attachment or file field of a later Integration Action, such as a Gmail or Google Drive action.
  • Only files in the working folder count. Files inside subfolders are not attached, and neither are mounted workspace files under files/.
  • Up to 100 files per run, 100 MB each and 500 MB in total.
  • A later Execute Code node sees the file’s name and size, not its content. Read the file with Read File instead.

Work with Workspace files

The Workspace files section under the code lets your code work on files from Workspace files, the folder your team and coworkers share. Click Add files or folder, pick a file or folder, and choose its access in the menu beside it:
  • Read-only: your code reads it. Whatever the code does to it is discarded. A new row starts as Read-only.
  • Read and write: when the code succeeds, the files it changed are saved back to Workspace files.
The Execute Code panel with code that opens files/Customers/customers.db, and the Workspace files section with Customers/customers.db set to Read and write and Reference/rates.db set to Read-only

Two mounts: the database the code updates, Read and write, and reference data it only reads.

Before the code runs, each mount is copied into a folder named files in the code’s working folder, at the same path: Customers/customers.db becomes files/Customers/customers.db.
The path is spelled exactly as Workspace files stores it. Workspace files matches names whatever their case, but the code’s folder does not, so pick the file with the folder button beside File or folder rather than typing it. A path may also use {{…}}, like {{file_added_to_folder_1.file.path}}.
The Choose a file or folder dialog over the Workspace files section, with cust typed and customers.db highlighted

Pick a file or folder from Workspace files. Type part of a name to find it anywhere.

What is saved back

  • Changed files are found by their content. After the code ends, its Python process is shut down (which closes any database connection left open) and a fresh process compares every file with the copy taken before. Committed database changes are saved; an open transaction is not.
  • Nothing is overwritten. If someone saved the file in Workspace files while your code ran, the run’s version is saved beside it as name (conflicted copy).ext, listed in conflicts. A new file whose name is already taken is saved the same way. A file moved to the Trash while your code ran is saved again at its path.
  • Each run starts from the current files. Every run, and every pass of a Loop, copies the mounts in again. Saves of one file by one run within 10 minutes join one version.
Node Execution Details with workspaceFiles expanded: written holds Customers/customers.db with outcome versioned

The step's output: customers.db was saved back as a new version.

Up to 10 mounts per step. All mounts of a run together copy in at most 2,000 files and 256 MB, and 100 MB per file; past that, the step fails before your code runs. A path inside another mounted path is refused.

Use a SQLite database with Workspace files

A step-by-step guide: keep a database in Workspace files and update it from this node, safely.

Set workflow variables

Changing a variable’s value in the code changes nothing outside it. To update a workflow variable, call set_variable with the variable’s key and the new value:
It works like an Update Variable node that replaces the value:
  • The variable must already exist. Add it under Variables first.
  • The value is converted to the variable’s type, and later nodes read the new value.
  • On Variable Update triggers start as usual.
  • The variable’s name in your code holds the new value too.
set_variable returns the value as stored. When it cannot set the variable, it raises VariableError, with .code saying why:
Set the final value once, after a loop, rather than on every pass. Each call writes the variable and can start triggers.

Call your apps from code

Bind connected apps to the node, and your code can call their actions as ordinary Python functions: integrations.<app>.<action>(...). Loop over a hundred rows and post one Slack message for each, in a single step.
Bind apps in the node’s Integrations section: click Configure, pick the app, the connection and the actions the code may call.
Integrations section with Connected integrations: 2 integrations, 3 actions enabled, and a Configure button

The Integrations section of the node. Configure opens the list of bound apps.

Under the editor, Integration functions then lists every function you can call. Click one to insert it with its required arguments.
Integration functions panel listing googlesheets.batch_get, slack.send_message and slack.list_all_channels

Integration functions, grouped by app. Click a function to insert the call.

Execute Code integrations

How to bind apps, call them, handle errors, and when to choose code over an LLM node.

Write code with the editor’s help

The editor knows what this node can use: earlier nodes’ outputs, workflow variables, set_variable, and the functions of the apps you bound. It suggests them as you type and flags mistakes before you run.

Suggestions as you type

Type integ and pick integrations. The editor then lists the bound apps, then each app’s functions, then the arguments of the call you’re in. Next to each function you see what it does and its main arguments.
Completion list with send_message and list_all_channels, and a card describing send_message and its arguments

After integrations.slack. the editor lists Slack's enabled functions, with what each does.

Pick a function that has required arguments, and they arrive as fields to fill in. Type the value, then press Tab to jump to the next one.
send_message(channel=channel) with the channel field selected

A picked function arrives with its required arguments as fields. Tab moves to the next one.

Tab accepts the highlighted suggestion; with no suggestion open it indents. Esc closes the list.

What an argument takes

Inside a call, a hint above it shows the function’s arguments. Required ones are bold; the one you’re typing is underlined and described below. Anything still missing is listed in red.
Argument hint for send_message with markdown_text underlined and its description

The argument hint above an open call, describing markdown_text as you type it.

Hover a function name to read what it does and every argument it takes.

Problems before you run

The editor underlines what the call would refuse at run time:
  • an app that isn’t bound to this node, or a function that isn’t enabled
  • a required argument that’s missing, once the call is closed
  • an argument name the action doesn’t have
  • a set_variable key that isn’t a workflow variable
Hover the underline to see why. When there’s an obvious fix, a button applies it: Add channel, or Change to slack for a typo.
send_message underlined with the message Missing required argument(s): channel, and an Add channel button

A closed call without its required channel argument. Add channel fills it in.

integrations.slak underlined: No app "slak" is bound to this node. Did you mean slack? with a Change to slack button

A typo in the app name, with the fix one click away.

Full screen

Click the expand button next to Generate with AI for a large editor. The side panel holds Ask AI, the integration functions, the available variables and How it works. Click Exit full screen to go back; Esc stays with the editor, so it doesn’t close the view by accident.
Full-screen code view with the Ask AI panel, integration functions and available variables in a sidebar

Full screen: the editor on the left; Ask AI, functions and variables on the right.

Let AI write the code for you

Click Generate with AI. The full-screen view opens with Ask AI at the top of the side panel:
  1. Describe what the code should do, or, when there is code already, the change you want.
  2. Click Generate code (or Update code). The AI writes into the editor.
  3. Read the result. Press Ctrl+Z in the editor to undo it.
Ask AI panel with the instruction Skip rows without an email and log how many were skipped, and an Update code button

Ask AI rewrites the code in the editor. It knows the earlier nodes' outputs and this node's integration functions.

Things to ask for:
  • “Find all phone numbers and email addresses in the text”
  • “Calculate the total of all the prices and add 10% tax”
  • “For every qualified lead in the sheet, post a message to #sales”
  • “Skip rows without an email and log how many were skipped”
The AI writes code for the apps bound to this node, so bind them first. You can insert earlier nodes’ outputs into your request with {{.
Be specific: name the fields, the condition and what the step should return. Then check the code before you save. It runs for real, on your connected accounts.

Example: data transformation

Transform API response data into a specific format:

Example: regex extraction

Extract patterns from text:

Example: API call

Call a public web service directly with requests:
For services you’ve connected as apps, call the app from code instead. The call runs on your connection, and the code never sees a key or token.

Example: date and time calculations

Calculate business days, deadlines, etc:
More complete, step-by-step examples are in Execute Code scenarios.

Available libraries

Code runs on Python 3.12 with the standard library and these packages pre-installed:
Need a package that’s not available? Contact support to request additions.

Limits

input() doesn’t wait for anyone: it returns an empty string. To ask a person something, use a Human Step before or after the code.

Error handling

Use try / except to handle errors gracefully:

Troubleshooting

Security

Code runs in an isolated sandbox that is created for each run and deleted afterwards. It can reach the public internet, but not the platform’s internal network, and it holds no platform keys or tokens. Integration calls run outside the sandbox, on the connection you bound.

Tips

Use print() for debugging. Output appears in stdOut.
Keep code focused on one task. For complex logic, use multiple Execute Code nodes with clear purposes.
Return structured data with output_data(...) rather than printing strings. This makes it easier for later nodes to read specific values.

Settings

string
default:"Execute Code"
What to call this node (shown on the canvas). The node’s key follows it.
string
default:"execute_code_1"
A short code to reference this node’s result.
string
required
Your Python code. Earlier node outputs are available as variables named after their node key, like webhook_1["body"].
array
The apps this code may call, each with a connection and the actions it may use. Set it in the node’s Integrations section. See Execute Code integrations.
array
Files or folders from Workspace files to copy in under files/, each { path, mode }: mode is read (Read-only, the default) or write (Read and write). Up to 10; none by default. Set it in the Workspace files section. See Work with Workspace files.

Outputs

any
Whatever your code sent with output_data(...). Without it, the value of the last line, as text.
any
The value of the last line of code, as text.
string
Anything you printed with print().
string
Error messages if something went wrong. Any text here marks the step as failed.
number
0 if everything worked, something else if it didn’t.
boolean
True if the code ran without crashing.
number
How long it took to run (in milliseconds).
array
The files your code saved, each with its name, size and mimeType. Insert one into a later node’s file field to send or store it.
object
Only when apps are bound: how many app calls the code made, how many failed, and a list of the calls.
object
Only when the code called set_variable: each variable it set, and how many times.
array
Only when apps are bound: apps the code could not call, for example because the connection was removed, and why.
object
Only when files are mounted:
  • mounted: each mount, with path, mode, kind (file or folder), files and bytes copied in
  • written: each file saved back, with path, fileId, versionId, size and outcome (versioned, coalesced or created)
  • conflicts: each file not saved as a new version of the original, with path, savedAs, reason, fileId and versionId. With changed (someone saved the original meanwhile) or name_taken (a new file’s name was taken), it is saved beside it as a conflicted copy. With deleted (the original went to the Trash meanwhile), it is saved again at its own path
  • deletedInSandbox: the paths the code deleted, which stay in Workspace files
  • skipped: each file not saved, with path and reason
written, conflicts, deletedInSandbox and skipped cover read-and-write mounts only.

Execute Code scenarios

Step-by-step patterns: loops over records, reports, sync, routing.

Execute Code integrations

Call your connected apps from Python.

LLM

For understanding text, an LLM may fit better than code.

SQLite with Workspace files

Keep a database in Workspace files and update it from code.