Documentation Index Fetch the complete documentation index at: https://mintlify.com/directus/directus/llms.txt
Use this file to discover all available pages before exploring further.
Directus Flows is a powerful automation engine that allows you to create complex workflows triggered by events, schedules, webhooks, or manual execution.
Flow Triggers
Flows can be triggered by different events:
Event Trigger
Run flows when data changes occur:
{
trigger : 'event' ,
options : {
type : 'action' , // or 'filter'
scope : [ 'items.create' , 'items.update' ],
collections : [ 'articles' , 'pages' ]
}
}
Available Events
items.create - After item creation
items.update - After item update
items.delete - After item deletion
auth.login - User login
files.upload - File upload
Schedule Trigger
Run flows on a schedule using cron syntax:
{
trigger : 'schedule' ,
options : {
cron : '0 0 * * *' // Daily at midnight
}
}
Cron examples:
*/5 * * * * - Every 5 minutes
0 9 * * 1 - Every Monday at 9 AM
0 0 1 * * - First day of every month
Webhook Trigger
Create HTTP endpoints that trigger flows:
{
trigger : 'webhook' ,
options : {
method : 'POST' , // GET, POST, PUT, PATCH, DELETE
async : false , // Wait for completion
return : '$last' // Return last operation result
}
}
Access webhook:
POST https://your-project.directus.app/flows/trigger/{flow-id}
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json
{ "data" : "your payload"}
Manual Trigger
Allow users to trigger flows from the App:
{
trigger : 'manual' ,
options : {
collections : [ 'articles' ],
requireSelection : true , // Require items to be selected
location : 'item' // 'item' or 'collection'
}
}
Operation Trigger
Trigger flows programmatically from other flows or extensions:
Call from another flow:
// Using trigger-flow operation
{
operation : 'trigger-flow' ,
options : {
flow : 'target-flow-id' ,
payload : { /* data to pass */ }
}
}
Operations
Operations are the building blocks of flows. Chain operations together to create workflows.
Condition
Branch flow based on conditions:
{
operation : 'condition' ,
options : {
filter : {
status : { _eq : 'published' },
author : { _null : false }
}
},
resolve : 'operation-if-true' ,
reject : 'operation-if-false'
}
Create Item
Create records in collections:
{
operation : 'item-create' ,
options : {
collection : 'notifications' ,
payload : {
message : 'New article: {{$trigger.title}}' ,
user : '{{$trigger.author}}' ,
timestamp : '{{$NOW}}'
},
permissions : '$full' , // $public, $trigger, $full, or role UUID
emitEvents : true
}
}
Update Item
Modify existing records:
{
operation : 'item-update' ,
options : {
collection : 'articles' ,
key : '{{$trigger.key}}' ,
payload : {
view_count : '{{$trigger.view_count + 1}}' ,
last_viewed : '{{$NOW}}'
},
permissions : '$trigger'
}
}
Read Item
Fetch data from collections:
{
operation : 'item-read' ,
options : {
collection : 'articles' ,
key : '{{$trigger.article_id}}' ,
fields : [ 'title' , 'author.email' , 'categories.name' ],
permissions : '$full'
}
}
Delete Item
Remove records:
{
operation : 'item-delete' ,
options : {
collection : 'temp_data' ,
key : '{{$trigger.key}}' ,
permissions : '$full'
}
}
Send Email
Send emails with templates:
{
operation : 'mail' ,
options : {
to : '{{$trigger.author.email}}' ,
subject : 'Your article was published' ,
type : 'template' , // 'wysiwyg', 'markdown', or 'template'
template : 'article-published' ,
data : {
article_title : '{{$trigger.title}}' ,
article_url : 'https://example.com/articles/{{$trigger.slug}}'
}
}
}
HTTP Request
Call external APIs:
{
operation : 'request' ,
options : {
method : 'POST' ,
url : 'https://api.example.com/webhooks' ,
headers : {
'Authorization' : 'Bearer {{$env.API_TOKEN}}' ,
'Content-Type' : 'application/json'
},
body : JSON . stringify ({
event: 'article.published' ,
data: {
id: '{{$trigger.id}}' ,
title: '{{$trigger.title}}'
}
})
}
}
Manipulate data with JSONata:
{
operation : 'transform' ,
options : {
json : {
fullName : '$trigger.first_name & " " & $trigger.last_name' ,
tags : '$map($trigger.categories, function($v) { $v.name })' ,
publishedDate : '$trigger.date_published ~> $toMillis()' ,
metadata : ' {
"author" : $trigger . author . email ,
"wordCount" : $length ( $split ( $trigger . content , " " ))
} '
}
}
}
Execute Script
Run custom JavaScript/TypeScript:
{
operation : 'exec' ,
options : {
code : `
module.exports = async function({ data, accountability }) {
const axios = require('axios');
// Custom logic
const result = await axios.get('https://api.example.com/data');
return {
processed: data.items.length,
external: result.data
};
};
`
}
}
Log Message
Write to system logs:
{
operation : 'log' ,
options : {
message : 'Article {{$trigger.title}} was published by {{$trigger.author.email}}'
}
}
Sleep/Delay
Pause flow execution:
{
operation : 'sleep' ,
options : {
milliseconds : 5000 // 5 seconds
}
}
Throw Error
Stop flow execution with error:
{
operation : 'throw-error' ,
options : {
message : 'Invalid status transition'
}
}
Send Notification
Create in-app notifications:
{
operation : 'notification' ,
options : {
recipient : '{{$trigger.author}}' ,
subject : 'Your article needs review' ,
message : 'Article "{{$trigger.title}}" has been submitted for review' ,
collection : 'articles' ,
item : '{{$trigger.id}}'
}
}
Flow Variables
Access data within operations using template variables:
$trigger
Data from the flow trigger:
'{{$trigger.id}}'
'{{$trigger.title}}'
'{{$trigger.author.email}}'
$last
Result from the previous operation:
'{{$last.id}}'
'{{$last[0].title}}' // For array results
$accountability
Information about the user who triggered the flow:
'{{$accountability.user}}'
'{{$accountability.role}}'
'{{$accountability.ip}}'
$env
Environment variables (must be allowlisted):
FLOWS_ENV_ALLOW_LIST = "API_KEY,WEBHOOK_SECRET"
'{{$env.API_KEY}}'
'{{$env.WEBHOOK_SECRET}}'
Special Functions
{{$NOW}} - Current timestamp
{{$NOW('+1 day')}} - Relative time
{{$NOW('-7 days')}} - Past time
Flow Execution
Flows execute operations in order with error handling:
[
{
id: 'op1' ,
operation: 'item-read' ,
resolve: 'op2' , // Next operation on success
reject: 'error-handler' // Operation on failure
},
{
id: 'op2' ,
operation: 'condition' ,
resolve: 'send-email' ,
reject: 'log-skip'
},
{
id: 'send-email' ,
operation: 'mail'
},
{
id: 'error-handler' ,
operation: 'log' ,
options: { message: 'Failed to process: {{$last.message}}' }
}
]
Example Workflows
Auto-publish Scheduled Content
{
trigger : 'schedule' ,
options : { cron : '*/5 * * * *' }, // Every 5 minutes
operations : [
{
operation: 'item-read' ,
options: {
collection: 'articles' ,
query: {
filter: {
status: { _eq: 'scheduled' },
publish_date: { _lte: '$NOW' }
}
}
}
},
{
operation: 'item-update' ,
options: {
collection: 'articles' ,
keys: '{{$last.map(a => a.id)}}' ,
payload: { status: 'published' }
}
}
]
}
Sync to External CMS
{
trigger : 'event' ,
options : {
type : 'action' ,
scope : [ 'items.create' , 'items.update' ],
collections : [ 'articles' ]
},
operations : [
{
operation: 'request' ,
options: {
method: 'POST' ,
url: 'https://cms.example.com/api/sync' ,
headers: { 'X-API-Key' : '{{$env.CMS_API_KEY}}' },
body: JSON . stringify ({ article: '{{$trigger}}' })
}
}
]
}
Best Practices
Use Conditions for Flow Control
Add condition operations to prevent unnecessary operations and handle edge cases.
Use reject branches to handle failures and log errors for debugging.
Email operations are rate-limited. Use conditions to prevent spam.
Use Async Webhooks for Long Operations
Set async: true on webhook triggers that perform time-consuming tasks.