7.5 For-Each Loops
The For-Each Loop is the core pattern for processing every item in a list with AI or any automation that takes time, and then collecting all results back into the parent row once every item is finished.
Tutorial first?
If you haven't built one yet, start with 5.4 For-Each Loops in the tutorial for a step-by-step walkthrough.
Overview
The pattern involves three connected parts:
Parent Row
│
├─ Sub-taible column (list of items)
│ │
│ ├─ Child Row 1 ──► [AI / API / Code column] ──► Done ✅
│ ├─ Child Row 2 ──► [AI / API / Code column] ──► Done ✅
│ └─ Child Row N ──► [AI / API / Code column] ──► Done ✅
│ │
│ (Completion tracker fires when ALL are Done)
│ │
├─ Pull Data column ◄────────────────┘ (collects results from children)
│
└─ Downstream columns (summarize, aggregate, send, ...)Without this pattern, parent columns that depend on child results fire immediately when first triggered — before the children have finished their async work — and produce partial or empty output.
With this pattern, the parent waits for a signal that all children are done before collecting results.
Configuration Reference
Part 1: Completion Tracking (sub-taible column in parent)
Completion tracking is configured on the sub-taible column in the parent taible — the column that holds the link to the child taible.
Where to find it: Edit column → scroll to "Completion Tracking" section.
| Setting | Type | Description |
|---|---|---|
| Track Completion | Toggle | Enables watching for all child rows to reach Done state |
| Track Column | Text | The technical name of the child column to monitor (e.g. analysis) |
How it works:
When "Track Completion" is enabled, the system monitors all child rows that share the same parent_row_id. Every time a child row's tracked column changes state, the system checks whether every sibling row (all children of the same parent) has the tracked column in Done state.
When the last child crosses into Done, the system automatically re-triggers all dependent columns in the parent row that are waiting for sub-taible completion.
Track Column must be the technical name
Use the column's internal name (lowercase, underscores) — the same name shown in template expressions. Not the display label. For example: analysis, not Analysis or AI Analysis.
Part 2: Pull Data Column (in parent)
The Pull Data node is the standard way to collect child results into the parent. It reads a single column from all child rows belonging to the current parent and returns the values as a list.
Where to find it: Add Column → Pull Data
| Setting | Default | Description |
|---|---|---|
| Source Taible | — | The child (sub-) taible to pull from |
| Source Column | — | Which column's values to collect |
| Filter by Parent Row | ON | Only pull rows belonging to the current parent row. Leave ON for For-Each loops. |
| Wait for All Rows to Complete | ON | If any child row's source column is not yet Done, skip this run and wait to be re-triggered. |
Output: A list of values, one entry per child row that has a non-empty value in the source column.
// Example output for 3 children:
["Analysis of topic A...", "Analysis of topic B...", "Analysis of topic C..."]The output type of the Pull Data column matches the child column's output type, wrapped in a List.
Part 3: Run Configuration (Pull Data column)
For the pull data column to be triggered by sub-taible completion, it must declare the sub-taible column as a dependency in its Run Configuration.
Dependency to add: The sub-taible column in the parent taible (the one with Track Completion enabled).
This is what connects the completion signal from Part 1 to the Pull Data column in Part 2. Without this dependency the re-trigger from Part 1 won't reach the Pull Data column.
Full Setup Checklist
In the child (sub-) taible:
- [ ] Add the column that does the work (AI, API, Custom Code, etc.)
- [ ] Set that column's dependency on the input column(s)
In the parent taible — sub-taible column:
- [ ] Open column settings → Completion Tracking section
- [ ] Enable Track Completion
- [ ] Set Track Column to the child column's technical name
In the parent taible — Pull Data column:
- [ ] Source Taible: the sub-taible
- [ ] Source Column: the child column to collect
- [ ] Filter by Parent Row: ON
- [ ] Wait for All Rows to Complete: ON
- [ ] Run Configuration → dependency on the sub-taible column
In the parent taible — downstream column (summarize, report, etc.):
- [ ] Dependency on the Pull Data column
- [ ] Run mode: Dependent - Once (runs when Pull Data delivers a value)
Execution Flow
The exact sequence of events when a parent row is created with a list of items:
1. Parent row created
2. Sub-taible column receives list data
3. System creates one child row per list item
4. Each child row's work column is queued and runs (in parallel)
... time passes (seconds to minutes depending on workload) ...
5. Child row #1 finishes → completion check: 1/N done, skip
6. Child row #2 finishes → completion check: 2/N done, skip
...
7. Child row #N finishes → completion check: N/N done → ALL DONE
8. System re-triggers parent row's dependent columns
9. Pull Data column runs:
- Checks all child rows → all Done ✅
- Collects values → publishes list
10. Downstream parent columns run (summarize, send, etc.)When NOT to Use Completion Tracking
Completion tracking adds overhead. You don't need it when:
- Child columns are instant (simple math, string manipulation) — the children finish before the parent dependency check even runs. Use a regular dependency instead.
- The parent only needs partial results — e.g., "notify me when any child finds a match." Use a regular dependency without "wait for all."
- Children are processed one at a time (rate-limited) and the parent should accumulate results incrementally. Use a different aggregation strategy.
Use completion tracking specifically for: AI calls, external API calls, web scraping, file processing — anything async that takes unpredictable time.
Relationship to Other Patterns
| Pattern | When to use |
|---|---|
| For-Each Loop (this page) | Process N items in parallel, collect all results when done |
| Parent → Child data flow | Pass parent data down to children as input (see 7.3) |
| Simple roll-up | Children have instant calculations; aggregate with Custom Code in parent |
| Cross-row analysis | Pull data from a completely separate taible, not a sub-taible (see 10.3) |
Common Patterns
Pattern: AI Batch Analysis → Summary
Parent: Report Request
└─ items (sub-taible) ── Track Completion: "analysis"
├─ Child: item_name → analysis (LLM)
└─ ... N children
Parent: all_analyses (Pull Data from sub-taible.analysis, Wait=ON)
Parent: final_summary (LLM, depends on all_analyses)Pattern: API Enrichment → Aggregated Result
Parent: Company
└─ employees (sub-taible) ── Track Completion: "enriched_profile"
├─ Child: name, email → enriched_profile (API call)
└─ ... N children
Parent: all_profiles (Pull Data, Wait=ON)
Parent: company_summary (depends on all_profiles)Pattern: Document Processing → Risk Report
Parent: Contract
└─ clauses (sub-taible) ── Track Completion: "risk_assessment"
├─ Child: clause_text → risk_assessment (LLM)
└─ ... N children
Parent: clause_risks (Pull Data, Wait=ON)
Parent: overall_risk_score (Custom Code, depends on clause_risks)Troubleshooting
Parent fires before children are done
Symptom: Pull Data returns fewer items than expected, or returns null/empty.
Cause: "Wait for All Rows to Complete" is not enabled on the Pull Data column, or "Track Completion" is not enabled on the sub-taible column (so no re-trigger signal is sent).
Fix: Enable both settings. Both are required.
Parent never fires after children complete
Symptom: All child rows show "Done" but the parent Pull Data column stays Idle.
Cause 1: "Track Completion" is enabled but "Track Column" doesn't match the child column name. The system checks for Done on the named column — a typo means the check never succeeds.
Cause 2: The Pull Data column is not listed as a dependency of the sub-taible column (or vice versa). Check Run Configuration.
Cause 3: One or more child rows failed (red status). The system only fires when all rows are Done, not when some are Failed. Fix the failing child rows first.
Results are correct but downstream column doesn't run
The downstream column (e.g., final_summary) must declare the Pull Data column (all_analyses) as a dependency. Without this, it won't know to re-run when Pull Data delivers a value.
Pull Data returns an empty list even though children are Done
Check that the source column name in Pull Data matches the child column's technical name exactly. Also verify that the child column's cells actually contain data (not null/empty).
See Also
- 5.4 For-Each Loops (Tutorial) — step-by-step tutorial
- 7.3 Working with Sub-Taibles — general sub-taible data flow
- 10.3 Data Aggregation Patterns — other aggregation strategies
- 4.1 Understanding Dependencies — how column dependencies work