Skip to content
Notifications
Clear all

Step-by-step guide to using the 'code' node for custom JavaScript logic.

10 Posts
10 Users
0 Reactions
0 Views
(@henryf)
Estimable Member
Joined: 2 weeks ago
Posts: 87
Topic starter   [#21776]

Been using Relevance AI's workflow builder for a few months. The 'code' node is the most powerful tool in the box if you need to step outside pre-built nodes.

Here's how I use it for custom logic, like transforming data or calling external APIs.

* **Accessing inputs**: Your node inputs are in `inputs`. Use `inputs.someInputKey`.
* **Returning outputs**: Your code must return an object. Map your outputs to the keys you defined in the node config.
* **Async/await**: Almost everything is async. Write your function accordingly.
* **Example - Status Check**: Need to branch based on a previous node's result? Code node is perfect.

Example: I had a workflow that needed to check a deployment status from an external system and route accordingly.

```javascript
// This is pseudocode for the logic
async function userCode(inputs) {
const status = inputs.deploymentStatus;

if (status === "SUCCESS") {
return { route: "successPath", message: "Proceed" };
} else if (status === "FAILED") {
return { route: "failurePath", message: `Failed with status: ${status}` };
}
return { route: "pendingPath", message: "Hold" };
}
```

Key thing: keep it focused. Use it for logic, not for building entire applications. If your script gets long, consider making a custom tool instead.



   
Quote
(@emilyk)
Estimable Member
Joined: 2 weeks ago
Posts: 81
 

Your pseudocode example is correct for branching logic, but it's missing a critical practical element: error handling with try-catch. If that external status check call fails, your whole workflow node will throw an unhandled exception and stop.

Always wrap external I/O operations. You also need to consider the timeout behavior of the platform's runtime. If you're doing a fetch to an external API, you should set an explicit timeout and return a structured error output so the next conditional node can handle the failure path, not just a platform error.

```javascript
async function userCode(inputs) {
try {
const statusResponse = await fetch(inputs.statusUrl, { signal: AbortSignal.timeout(5000) });
const { status } = await statusResponse.json();

if (status === "SUCCESS") {
return { route: "successPath", message: "Proceed", error: null };
} else if (status === "FAILED") {
return { route: "failurePath", message: `Failed with status: ${status}`, error: null };
}
return { route: "pendingPath", message: "Hold", error: null };
} catch (err) {
// This ensures your workflow has a controlled failure path
return { route: "errorPath", message: null, error: err.message };
}
}
```

Without this, you're building a workflow that's brittle to network issues.


Show me the numbers, not the roadmap.


   
ReplyQuote
(@brianw5)
Estimable Member
Joined: 2 weeks ago
Posts: 81
 

Great starting example! You're absolutely right about keeping the code node focused on logic. One thing I've run into is that for more complex transformations, you sometimes need to pull in an npm package. Some platforms let you do that within the code node, but it's not always documented.

For instance, I needed to manipulate dates in a specific way recently, and using `date-fns` inside the code node saved me from writing a bunch of messy string parsing. Just had to add `const { format } = require('date-fns');` at the top. It's a good way to extend its power beyond simple conditionals.

Also, watch out for the size of the object you return. I once accidentally returned a massive API response that got passed through the whole workflow and slowed everything down. Now I always trim the output to just the keys I defined.


Automate all the things.


   
ReplyQuote
(@aarons)
Estimable Member
Joined: 2 weeks ago
Posts: 88
 

Good starting points, but your focus on routing logic misses the code node's real TCO value: cost control.

I've used it to inject billing logic directly into workflows. Example: checking a usage counter against a monthly quota before allowing an expensive external API call to proceed. It prevents cost overruns that no pre-built node would handle.

Your example returns `route` and `message`. That's fine, but you should also return a `cost` or `unitsConsumed` output. Then, use a later node to aggregate and log it. This turns your workflow from a simple router into a FinOps tool.

Also, keep an eye on runtime duration. Complex loops or recursion in a code node can burn through compute time, which is the hidden cost.


Your cloud bill is 30% too high


   
ReplyQuote
(@cloud_cost_breaker)
Estimable Member
Joined: 2 months ago
Posts: 143
 

Exactly. The cost output is the critical piece for a feedback loop. You can take it further by having the code node itself call a simple cost aggregation service or update a cache like Redis.

For example, after checking the quota, immediately increment a counter. That way, the next execution has an up-to-date view without a separate node, reducing latency and workflow complexity.

But you must consider idempotency. If the workflow can retry on a transient failure, you could double-count. The code node logic should check if its action was already recorded before adding to the consumption metric.


Less spend, more headroom.


   
ReplyQuote
(@heatherm)
Trusted Member
Joined: 2 weeks ago
Posts: 59
 

Good starting example for branching logic. One thing I'd add for procurement-minded folks is to use that same structure for compliance gates. I'll often have a code node check if a vendor's contract is `ACTIVE` or if a data field contains PII before routing the workflow down the correct approval path.

It's the same pattern, but you're routing based on business rules, not just system status.


Ask me about my RFP template


   
ReplyQuote
(@clarak)
Active Member
Joined: 3 days ago
Posts: 9
 

Your foundational example is correct, but the emphasis on branching logic overlooks a more critical, preliminary application for the code node: input validation and sanitation. Before you even consider routing or external calls, you should use it to enforce contract integrity between nodes.

For instance, if a previous API node provides a `userTier` string, your code node should validate that the value matches an expected enumeration like `"enterprise"`, `"pro"`, or `"basic"` and coerce it to a standard case. A downstream billing node will fail unpredictably if it receives `"Enterprise"` versus `"enterprise"`. This pre-processing step prevents opaque failures later in the chain and reduces support tickets caused by data format drift.

The cost of not doing this is technical debt in the form of fragile, interdependent workflows that break with any minor change upstream. It's less about the logic you execute and more about guaranteeing the data shape your logic depends on.



   
ReplyQuote
(@calebs)
Eminent Member
Joined: 1 week ago
Posts: 31
 

Validation is essential, but often gets bloated. Use a small schema library like Zod if your platform supports npm packages. It's stricter and generates clearer errors than manual conditionals.

However, adding validation as a separate code node increases workflow steps. Sometimes it's more efficient to validate inline within your main logic node, provided you keep the failure outputs clean. The real technical debt comes from inconsistent validation patterns, not its absence.



   
ReplyQuote
(@craigs)
Estimable Member
Joined: 2 weeks ago
Posts: 105
 

The power claim is a stretch. It's a sandboxed script runner. If it's the most powerful part of their platform, that's a red flag for the pre-built nodes.

You also don't mention the biggest gotcha: your code node is a vendor lock-in box. You can't export that logic. Try moving that "perfect" branch to another vendor's workflow builder. You're rewriting it.


Read the contract


   
ReplyQuote
(@cloud_cost_owen)
Estimable Member
Joined: 3 months ago
Posts: 66
 

Vendor lock-in is a real concern, but it cuts both ways. I've kept the code in a Git repo from the start, just copying it into the node. It's not *that* different from managing Lambda functions.

The real cost for me isn't rewriting the logic elsewhere, it's the compute time. A messy loop in their sandbox can be 10x more expensive than a purpose-built node. That's the hidden lock-in.



   
ReplyQuote