This guide explains how to add new flows to the repository following the folder structure and namespace convention.
The folder structure automatically determines the flow namespace:
kestra/flows/PART1/PART2/PART3/flow_name.yml
↓
namespace: PART1.PART2.PART3
id: flow_name
| File Path | Expected Namespace | Expected ID |
|---|---|---|
kestra/flows/company/hello_world.yml |
company |
hello_world |
kestra/flows/company/_services/github/sync.yml |
company._services.github |
sync |
kestra/flows/company/pipelines/daily_sync.yml |
company.pipelines |
daily_sync |
kestra/flows/analytics/reports/monthly.yml |
analytics.reports |
monthly |
Organize flows by logical namespace. Recommendations:
- Use company/project name as root (e.g.,
watxer/) - Group related flows in subfolders (e.g.,
_services/,pipelines/) - Use descriptive names in lowercase with underscores
mkdir -p kestra/flows/company/pipelinesCreate the .yml file with the name matching the desired id:
# kestra/flows/company/pipelines/daily_sync.yml
id: daily_sync
namespace: company.pipelines
description: Daily data synchronization
tasks:
- id: fetch_data
type: io.kestra.plugin.core.http.Request
uri: https://api.example.com/data
- id: process
type: io.kestra.plugin.scripts.python.Script
script: |
print("Processing data...")IMPORTANT: The namespace and id in the YAML must match the folder convention. The validation hook will reject if they don't match.
Before committing, run the validation script:
npm run validateThe script validates:
- ✅ Flow
id= file name - ✅ Flow
namespace= folder path (converted with.) - ✅ Valid YAML syntax (via Docker)
Use the Docker wrapper to validate a specific flow:
./bin/kestra.sh flow validate --local kestra/flows/watxer/pipelines/daily_sync.ymlgit add kestra/flows/company/pipelines/daily_sync.yml
git commit -m "Add daily sync pipeline"
git push origin staging # or prod, depending on environmentGitHub Actions will:
- Validate structure (if PR)
- Automatically deploy to Kestra (if push to
prodorstaging)
- Use short, descriptive names
- Prefer lowercase
- Use underscore
_if needed (e.g.,_services) - Avoid too many levels (maximum 4-5 recommended)
Good:
company._services.githubanalytics.reportsetl.daily
Avoid:
MyCompany.Services.Integration.External.GitHub(too long)temp(not descriptive)
- Use snake_case (lowercase with underscores)
- Be descriptive about what the flow does
- Avoid generic IDs like
flow1,test
Good:
search_repositoriessend_slack_notificationmonthly_report
Avoid:
flow1(not descriptive)SearchRepositories(use snake_case)temp_test(temporary)
kestra/flows/
company/
sales/ # Sales flows
marketing/ # Marketing flows
analytics/ # Analytics flows
kestra/flows/
company/
_services/ # External API integrations
pipelines/ # ETL and data processing
notifications/ # Alert sending
kestra/flows/
company/
_services/
github/
slack/
salesforce/
pipelines/
daily/
hourly/
analytics/
reports/
If the flow uses static files (configs, scripts, etc), place them in kestra/files/ following the same namespace:
kestra/
flows/
company/
pipelines/
etl_process.yml # namespace: company.pipelines
files/
company/
pipelines/
config.json # Accessible by flow via namespace files
transform_script.py
In the flow, access via:
tasks:
- id: read_config
type: io.kestra.plugin.core.storage.LocalFiles
inputs:
config.json: "{{ namespace.files.read('config.json') }}"❌ kestra/flows/company/pipelines/daily_sync.yml
Namespace mismatch: expected 'company.pipelines', got 'company.pipeline'
Solution: Fix the namespace in the YAML to match the folder path.
❌ kestra/flows/company/pipelines/daily_sync.yml
ID mismatch: expected 'daily_sync', got 'daily-sync'
Solution: Rename the file or fix the id in the YAML.
❌ Syntax validation failed: kestra/flows/company/pipelines/daily_sync.yml
Solution: Run ./bin/kestra.sh flow validate --local <file> to see detailed error.