Back to Capabilities

Code Execution

Sandboxed JavaScript execution with isolated-vm for custom transformations, data processing, and business logic within workflows.

Imagine...

You need custom business logic that doesn't fit into a simple database query. Maybe you're calculating customer lifetime value with a complex formula. Or scoring leads based on 15 different signals. Or transforming API responses into exactly the format you need.

The built-in tools get you 90% of the way there. But that last 10%? That's YOUR specific logic.

You

"I need to calculate customer health scores. It's based on their usage frequency, support ticket count, payment history, and feature adoption. Each factor has different weights depending on their plan tier."

Your Awareness

"I'll write a Python function that takes all those inputs and calculates the score. Should I use a weighted average or something more sophisticated?"

You

"Weighted average is fine. Enterprise customers should have 2x weight on feature adoption. And if they've had more than 3 support tickets in the last month, deduct 20 points."

Your Awareness

*Writes Python function with your exact logic, adds it to workflow*

"Done. Here's the function. I tested it on your top 10 customers—scores range from 42 to 94. Want me to run it on everyone and add the scores to the database?"

You

"Yes. And recalculate it daily so the scores stay fresh."

Your Awareness

"Perfect. Created a daily workflow that recalculates health scores for all customers and updates the database. Your dashboard will show the latest scores automatically."

This isn't magic. This is collaboration.

When you need custom logic that's specific to your business, just describe it. Your Awareness writes the code and makes it work.

Execution Modes

Sandboxed (Recommended)

isolated-vm with memory and CPU limits

  • Memory limit: 128 MB
  • Timeout: 10 seconds
  • No file system access
  • No network access
  • No dangerous APIs (eval, Function constructor blocked)
  • • Safe for user-provided code

Trusted (Internal Only)

Direct execution without sandboxing

  • No memory limits
  • No CPU limits
  • Full Node.js access
  • ⚠️ SECURITY RISK - Only for system-defined code
  • • Never use for user/AI-generated code

Timeout Fallback

Basic timeout wrapper when isolated-vm unavailable

  • • 10 second timeout
  • • No memory limits
  • • Used when isolated-vm not installed
  • • Not recommended for production

Language Support

Currently JavaScript only

  • JavaScript: ✅ Supported
  • TypeScript: ❌ Not supported (transpile before execution)
  • Python: ❌ Not supported
  • Other languages: ❌ Not supported

Code Node in Workflows

Add a Code node to your workflow to transform data, apply business logic, or perform calculations:

{
  "id": "transform_data",
  "type": "code",
  "name": "Calculate Totals",
  "language": "javascript",
  "sandbox": true,  // Always use sandboxed execution
  "code": `
    // Input: { orders: [...] }
    // Context: { variables: {...}, userId: "..." }

    const total = input.orders.reduce((sum, order) => {
      return sum + (order.quantity * order.price);
    }, 0);

    const itemCount = input.orders.length;
    const avgPrice = total / itemCount;

    console.log(`Processed ${itemCount} orders, total: $${total}`);

    return {
      total,
      itemCount,
      avgPrice,
      timestamp: new Date().toISOString()
    };
  `
}

// Node output available to subsequent nodes:
// {{transform_data.output.total}}
// {{transform_data.output.avgPrice}}

Available APIs in Sandbox

Global Objects

  • input - Node input data
  • ctx - Workflow context (variables, userId)
  • console - Logging (log, info, warn, error)
  • JSON - JSON.parse, JSON.stringify
  • Math - Math operations
  • Date - Date/time handling
  • Array - Array methods
  • Object - Object methods
  • String - String methods
  • RegExp - Regular expressions

Blocked APIs

  • require() - No module imports
  • import - No ES6 imports
  • fs - No file system access
  • fetch - No network requests
  • XMLHttpRequest - No HTTP
  • WebSocket - No websockets
  • process - No process access
  • setTimeout - No timers
  • eval - No dynamic code execution
  • Function() - No function constructor

Common Patterns

Data Transformation

// Input: { users: [{firstName: "John", lastName: "Doe"}, ...] }
return input.users.map(user => ({
  fullName: `${user.firstName} ${user.lastName}`,
  email: `${user.firstName.toLowerCase()}.${user.lastName.toLowerCase()}@example.com`
}));

// Output: [{ fullName: "John Doe", email: "john.doe@example.com" }, ...]

Filtering & Aggregation

// Input: { transactions: [{amount: 100, category: "food"}, ...] }
const filtered = input.transactions.filter(t => t.amount > 50);

const byCategory = filtered.reduce((acc, t) => {
  acc[t.category] = (acc[t.category] || 0) + t.amount;
  return acc;
}, {});

return {
  totalTransactions: filtered.length,
  totalAmount: filtered.reduce((sum, t) => sum + t.amount, 0),
  byCategory
};

// Output: { totalTransactions: 42, totalAmount: 5230, byCategory: {...} }

Conditional Logic

// Input: { score: 85, attendance: 0.92 }
const grade = input.score >= 90 ? 'A' :
              input.score >= 80 ? 'B' :
              input.score >= 70 ? 'C' :
              input.score >= 60 ? 'D' : 'F';

const status = input.attendance >= 0.9 && input.score >= 70
  ? 'passing'
  : 'needs_improvement';

console.log(`Student grade: ${grade}, status: ${status}`);

return { grade, status, passesThreshold: status === 'passing' };

Date Manipulation

// Input: { events: [{date: "2024-01-15", ...}, ...] }
const now = new Date();
const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);

const recentEvents = input.events.filter(e => {
  const eventDate = new Date(e.date);
  return eventDate >= weekAgo && eventDate <= now;
});

return {
  recentCount: recentEvents.length,
  oldestRecent: recentEvents[0]?.date,
  newestRecent: recentEvents[recentEvents.length - 1]?.date
};

Access Workflow Context

// Context: { variables: { apiKey: "...", threshold: 100 }, userId: "user_123" }
const userApiKey = ctx.variables.apiKey;
const threshold = ctx.variables.threshold;
const currentUser = ctx.userId;

console.log(`Processing for user: ${currentUser}`);

return input.items.filter(item => {
  return item.value > threshold && item.userId === currentUser;
}).map(item => ({
  ...item,
  processedBy: currentUser,
  processedAt: new Date().toISOString()
}));

Error Handling

Code execution errors are captured and returned with context:

// Error response structure
{
  "success": false,
  "error": "ReferenceError: undefinedVariable is not defined",
  "logs": [
    "Starting processing...",
    "[ERROR] Unexpected error occurred"
  ]
}

// Timeout error
{
  "success": false,
  "error": "Code execution timed out (10s limit)",
  "logs": []
}

// Memory limit error (isolated-vm)
{
  "success": false,
  "error": "Isolate was disposed during execution",
  "logs": []
}

Configure node-level error handling with onError: "fail" (stop workflow), "continue" (skip node), or "retry" (retry with backoff).

Performance Considerations

✅ Best Practices

  • • Keep code simple and focused
  • • Avoid large loops (use built-in Array methods)
  • • Minimize object copies
  • • Use early returns to avoid unnecessary work
  • • Leverage native methods (filter, map, reduce)
  • • Test with realistic data sizes

❌ Avoid

  • • Infinite loops (hits timeout)
  • • Large in-memory arrays (>1M items)
  • • Recursive functions without base case
  • • String concatenation in loops (use array join)
  • • Deep object nesting (>10 levels)
  • • Complex regex on large strings

Debugging

Use console.log to debug code execution. Logs are captured and returned with results:

console.log('Starting transformation');
console.log('Input data:', JSON.stringify(input, null, 2));
console.log('User ID:', ctx.userId);

const result = input.items.map((item, idx) => {
  console.log(`Processing item ${idx}: ${item.name}`);
  return { ...item, processed: true };
});

console.log('Transformation complete, count:', result.length);
return result;

// Execution result includes logs:
{
  "success": true,
  "result": [...],
  "logs": [
    "Starting transformation",
    "Input data: {...}",
    "User ID: user_123",
    "Processing item 0: Widget",
    "Processing item 1: Gadget",
    "Transformation complete, count: 2"
  ]
}