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:
| outputs.getUserName.name // "John Doe"
outputs.getUserRole.role // "admin"
outputs.accessCheck.allowed // true
|
Examples:
| // 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).
| signals.blockName.signalName
|
Example:
| 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
| `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
| outputs.calculation.result * 1.2 // Mathematical operations
outputs.metrics.count + outputs.metrics.errors // Addition
|
Arrays and Objects Operations
| 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
| 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
|
Use anonymous functions for multi-step processing:
| (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.