Skip to content

Using Input and Output Event Data

Understanding data flow through your automation is important for building effective Flows. This explains how to access, reference, and manipulate event data.

Event Accumulation»

Events accumulate data as they flow through blocks. Each block adds its output to existing event data using the block's camelCase name as the key.

Example flow: "Get User Name" → "Get User Role" → "Access Check"

Final event structure:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "getUserName": {
    "name": "John Doe",
    "email": "johndoe@example.org"
  },
  "getUserRole": {
    "role": "admin"
  },
  "accessCheck": {
    "allowed": true
  }
}

Accessing Data in Configuration»

The outputs Variable»

Access outputs of previous blocks through the outputs variable:

1
2
3
outputs.getUserName.name     // "John Doe"
outputs.getUserRole.role     // "admin"
outputs.accessCheck.allowed // true

Examples:»

1
2
3
4
5
6
7
8
// Slack message
`Hello <@${outputs.getUserName.name}>! Your role is: ${outputs.getUserRole.role}`

// Conditional logic
outputs.accessCheck.allowed && outputs.getUserRole.role === 'admin'

// Dynamic URL
`https://api.example.com/users/${outputs.getUserName.email}/permissions`

Referencing signals»

While outputs gives you access to event data from previous blocks, the signals global lets you reference signals from blocks with lifecycles (e.g. an S3 Bucket Resource).

1
signals.blockName.signalName

Example:

1
signals.myS3Bucket.arn  // AWS S3 bucket ARN reference

Block Name Conversion»

Block names automatically convert to camelCase for event data keys. Numbers are included in the camelCase name, and content within parentheses is automatically excluded from the conversion.

Block Name Data Key
"Get User Name" getUserName
"API Response" apiResponse
"Process Data 2" processData2
"Test Block (3)" testBlock
"Profile (Beta)" profile

Common Data Operations»

String Data»

1
2
3
`User: ${outputs.userLookup.name} (${outputs.userLookup.email})` // String interpolation
outputs.userLookup.name.toUpperCase() // Data transformation
outputs.userLookup.email.includes('@company.com') // String method check

Numeric Data»

1
2
outputs.calculation.result * 1.2 // Mathematical operations
outputs.metrics.count + outputs.metrics.errors // Addition

Arrays and Objects Operations»

1
2
3
4
5
6
outputs.userList.users.length // Array length
outputs.userList.users.map(user => user.name) // Array transformation
outputs.userList.users.filter(user => user.active) // Array filtering

outputs.apiResponse.data.items[0].id // Array element access
outputs.configuration.settings.timeout // Property access

Boolean Logic»

1
2
3
4
5
6
outputs.validation.isValid && outputs.permissions.hasAccess // Boolean operations
outputs.userProfile.role === 'admin' // Property check
!outputs.check.failed || outputs.retry.available // Fallback logic
`Display Name: ${outputs.getUserMetadata.user.display_name || 'Not set'}` // Default assignment
outputs.error.occurred ? `Error: ${outputs.error.message}` : `Success: Processed ${outputs.result.count} items` // Conditional logic
outputs.performance.responseTime > 1000 // Comparison

Complex Transformations»

Use anonymous functions for multi-step processing:

1
2
3
4
5
6
7
8
9
(function() {
  const users = outputs.userQuery.results || [];
  const activeUsers = users.filter(user => user.status === 'active');
  return {
    total: activeUsers.length,
    names: activeUsers.map(user => user.name),
    lastLogin: Math.max(...activeUsers.map(user => new Date(user.lastLogin).getTime()))
  };
})()

Testing Your Expressions»

After connecting blocks, Spacelift shows input schemas so you know what data is available. Use the debug feature to send test events and verify your expressions work correctly.