Crash Course on Celery Primitives
Feb. 10, 2026 by John Rei Enriquez
Quick speed run on Celery Primitives
🥬 Celery Primitives Explained
Understanding Groups, Chains, Chords & Chunks
📦 Group
Execute multiple tasks in parallel and collect all their results. Think of it as "run all these tasks at the same time."
# Execute 3 tasks in parallel
job = group(
process_image.s(img1),
process_image.s(img2),
process_image.s(img3)
)
result = job.apply_async()
# Get all results as a list
results = result.get() # [res1, res2, res3]
🎯 When to Use:
- Processing multiple independent items (e.g., batch image processing)
- Making multiple API calls that don't depend on each other
- Running the same task with different inputs simultaneously
- When you need all results but order doesn't matter
⛓️ Chain
Execute tasks sequentially where each task's output becomes the input for the next task. Think of it as "do this, then do that with the result."
# Task 1 output → Task 2 input → Task 3 input
job = chain(
fetch_data.s(url), # Returns raw data
parse_data.s(), # Gets raw data, returns parsed
save_to_db.s() # Gets parsed data, returns ID
)
result = job.apply_async()
# Get only the final result
final_result = result.get() # Just the DB ID
🎯 When to Use:
- Data processing pipelines (fetch → transform → store)
- When each step depends on the previous step's output
- Multi-stage transformations (resize image → add watermark → compress)
- Workflows where order matters
🎵 Chord
A Group followed by a callback task. Run multiple tasks in parallel, wait for ALL to complete, then run one final task with all results. Think of it as "do all these in parallel, then do this with all the results."
# Run tasks in parallel, then aggregate results
job = chord(
[
analyze_log.s(log1),
analyze_log.s(log2),
analyze_log.s(log3)
]
)(create_report.s()) # Callback gets [res1, res2, res3]
result = job.get() # Returns the report
🎯 When to Use:
- Process multiple items then aggregate (analyze logs → create summary report)
- Parallel computation followed by consolidation (map-reduce pattern)
- Fetch data from multiple sources then combine
- When you need to do something with ALL results together
🍰 Chunk
Split a large batch of work into smaller groups that run in parallel. Think of it as "I have 1000 items, process them in batches of 100."
# Process 1000 emails in batches of 100
items = list(range(1000)) # Your data
job = send_email.chunks(items, 100) # 10 groups of 100
result = job.apply_async()
# Returns a GroupResult with 10 sublists
results = result.get() # [[res1-100], [res101-200], ...]
🎯 When to Use:
- Processing large datasets that would overwhelm if sent all at once
- Rate-limiting: control how many tasks run simultaneously
- Memory management: process data in manageable batches
- Bulk operations (send 10,000 emails in chunks of 100)
🔍 Quick Comparison
Understanding when to use each primitive
| Primitive | Execution | Result | Use When... |
|---|---|---|---|
| Group | All tasks in parallel | List of all results | Tasks are independent, need all results |
| Chain | Sequential (one after another) | Final task result only | Each step depends on previous output |
| Chord | Parallel + callback | Callback result | Need to aggregate parallel results |
| Chunk | Batched parallel | List of batch results | Large dataset, need resource control |
✅ YES → Use Chain
❌ NO → Continue...
❓ Do you have MANY items (100s/1000s)?
✅ YES → Use Chunk
❌ NO → Continue...
❓ Need to process all results together?
✅ YES → Use Chord
❌ NO → Use Group
🎯 Common Patterns Combined:
- Chain of Groups: Multiple parallel stages in sequence (fetch all data → process all data → save all data)
- Group of Chains: Multiple independent pipelines running in parallel
- Chord with Chain callback: Parallel work → sequential processing of results
- Chunks in Chord: Process huge dataset in batches, then aggregate