The simplest possible workflow example to help you understand the basics of Render Workflows. Perfect for beginners!
This example teaches the fundamental concepts:
- What is a Task? - A function decorated with
@app.taskthat can be executed as a workflow - What is a Subtask? - A task called by another task using
await - How to Orchestrate - Combining multiple tasks to create workflows
- How to Deploy - Getting your first workflow running on Render
Simple number processing to demonstrate workflow patterns without complex business logic. If you can understand this example, you can build any workflow!
calculate_and_process (multi-step orchestrator)
├── add_doubled_numbers
│ ├── double (subtask #1)
│ └── double (subtask #2)
└── process_numbers
├── double (subtask for item 1)
├── double (subtask for item 2)
└── double (subtask for item N)
A task is simply a Python function decorated with @app.task. It becomes a workflow step that Render can execute:
from render_sdk import Workflows
app = Workflows()
@app.task
def double(x: int) -> int:
"""A simple task that doubles a number"""
return x * 2
app.start()A subtask is when one task calls another task using await. This is how you compose workflows:
@app.task
async def add_doubled_numbers(a: int, b: int) -> dict:
# Call 'double' as a subtask using await
doubled_a = await double(a) # ← This is a subtask call!
doubled_b = await double(b) # ← This is also a subtask call!
return {
"sum": doubled_a + doubled_b
}- Reusability: Write
doubleonce, use it everywhere - Composition: Build complex workflows from simple building blocks
- Visibility: Render shows you each subtask execution in the dashboard
- Testing: Test individual tasks independently
- Python 3.10+
# Navigate to example directory
cd hello-world
# Install dependencies
pip install -r requirements.txt
# Run the workflow service
python main.pyThe service will start and register all tasks. You'll see output like:
Starting Hello World Workflow Service
Registered tasks:
- double(x)
- add_doubled_numbers(a, b)
- process_numbers(numbers)
- calculate_and_process(a, b, more_numbers)
Ready to accept task executions!
Service Type: Workflow
Build Command:
cd hello-world && pip install -r requirements.txtStart Command:
cd hello-world && python main.pyRequired:
RENDER_API_KEY- Your Render API key (from Render dashboard)
-
Create Workflow Service
- Go to Render Dashboard
- Click "New +" → "Workflow"
- Connect your repository
- Name:
hello-world-workflows
-
Configure Build Settings
- Build Command:
cd hello-world && pip install -r requirements.txt - Start Command:
cd hello-world && python main.py
- Build Command:
-
Set Environment Variables
- Add
RENDER_API_KEYin the Environment section - Get API key from: Render Dashboard → Account Settings → API Keys
- Add
-
Deploy
- Click "Create Workflow"
- Render will build and start your workflow service
Once deployed, test your workflows directly in the Render Dashboard:
- Go to your Workflow service in Render Dashboard
- Click the "Manual Run" or "Start Task" button
- Select the task you want to test
- Enter the task input as JSON in the text area
- Click "Start task"
Important: The hello-world workflow expects direct values and arrays, not JSON objects. Use 5 instead of {"x": 5}, and [3, 4] instead of {"a": 3, "b": 4}.
Recommended Starting Point: Start with double - the simplest possible task, then work your way up to more complex examples.
Test the basic task:
Task: double
Input:
5Expected output: 10
Test subtask calling:
Task: add_doubled_numbers
Input:
[3, 4]Expected output:
{
"original_numbers": [3, 4],
"doubled_numbers": [6, 8],
"sum_of_doubled": 14,
"explanation": "3 doubled is 6, 4 doubled is 8, sum is 14"
}This task calls double twice as subtasks!
Test subtask in a loop:
Task: process_numbers
Input:
[1, 2, 3, 4, 5]Expected output:
{
"original_numbers": [1, 2, 3, 4, 5],
"doubled_numbers": [2, 4, 6, 8, 10],
"count": 5,
"explanation": "Processed 5 numbers through the double subtask"
}This calls double as a subtask 5 times (once for each number)!
Test multi-step workflow:
Task: calculate_and_process
Input:
[2, 3, 10, 20, 30]This is the most complex example - it calls add_doubled_numbers and process_numbers as subtasks, which in turn call double multiple times. Watch the Render Dashboard to see the entire execution tree!
Once deployed, trigger workflows via the Render Client SDK:
from render_sdk import Render
# Uses RENDER_API_KEY environment variable automatically
render = Render()
# Call the simple double task
task_run = await render.workflows.run_task(
"hello-world-workflows/double",
{"x": 5}
)
result = await task_run
print(f"Result: {result.results}") # Output: 10
# Call the subtask orchestration example
task_run = await render.workflows.run_task(
"hello-world-workflows/add_doubled_numbers",
{"a": 3, "b": 4}
)
result = await task_run
print(f"Sum of doubled: {result.results['sum_of_doubled']}") # Output: 14The simplest possible task. Takes a number, doubles it, returns the result.
Purpose: Show what a basic task looks like.
Can be called as a subtask: Yes! Other tasks call this.
Demonstrates the fundamental subtask pattern.
What it does:
- Calls
double(a)as a subtask - Calls
double(b)as a subtask - Adds the results together
Purpose: Show how to call tasks as subtasks using await.
Key Pattern:
result = await double(a) # ← Subtask call with awaitDemonstrates calling a subtask in a loop.
What it does:
- Takes a list of numbers
- Calls
doubleas a subtask for each number - Collects all the results
Purpose: Show how to process lists/batches using subtasks.
Key Pattern:
for num in numbers:
doubled = await double(num) # ← Subtask call in a loopDemonstrates a multi-step workflow with multiple subtask calls.
What it does:
- Calls
add_doubled_numbersas a subtask - Calls
process_numbersas a subtask - Combines the results
Purpose: Show how to chain multiple subtasks to create complex workflows.
Key Pattern:
step1 = await add_doubled_numbers(a, b) # ← First subtask
step2 = await process_numbers(numbers) # ← Second subtask
# Combine resultsEvery workflow function needs the @app.task decorator:
from render_sdk import Workflows
app = Workflows()
@app.task
def my_task():
return "Hello World"
app.start()Tasks that call other tasks as subtasks must be async:
@app.task
async def orchestrator():
result = await subtask() # ← Calls another task
return resultUse await to call a task as a subtask:
result = await task_name(arguments)Without await, you're just calling a regular Python function!
All @app.task decorated functions are registered when defined. Call app.start() at the end of your module to start the workflow service and make all registered tasks available for execution.
Execute subtasks one after another:
@app.task
async def sequential():
step1 = await task_a()
step2 = await task_b(step1) # Uses result from step1
step3 = await task_c(step2) # Uses result from step2
return step3Execute subtasks where order doesn't matter:
@app.task
async def independent():
result_a = await task_a()
result_b = await task_b()
return combine(result_a, result_b)Process a list by calling a subtask for each item:
@app.task
async def batch_process(items: list):
results = []
for item in items:
result = await process_item(item)
results.append(result)
return resultsSubtasks can call other subtasks:
@app.task
async def level_1():
return await level_2()
@app.task
async def level_2():
return await level_3()
@app.task
def level_3():
return "Done!"Once you understand this example, check out:
- ETL Job - Learn data processing patterns with CSV files
- File Processing - Learn parallel execution with
asyncio.gather() - Data Pipeline - Learn complex multi-stage workflows
- OpenAI Agent - Learn advanced patterns with AI integration
- File Analyzer - Learn how to call workflows from APIs using Client SDK
Make sure:
- The service is deployed and running
- The task name matches exactly (case-sensitive)
- You're using the correct service slug
Make sure:
requirements.txtincludesrender-sdk>=0.5.0- Build command is running correctly
- Python version is 3.10 or higher
Make sure:
- Your task function is marked
async - You're using
awaitbefore the task call - Both tasks are decorated with
@app.task
- Python-only: Workflows are only supported in Python via render-sdk
- No Blueprint Support: Workflows don't support render.yaml blueprint configuration
- Service Type: Deploy as a Workflow service on Render (not Background Worker or Web Service)
- Async Functions: Tasks that call subtasks must be declared as
async
Start simple, build powerful workflows!