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.
Introduction
Directus supports GraphQL subscriptions for real-time updates when items are created, updated, or deleted in your collections. Subscriptions use WebSockets to maintain a persistent connection and push updates to clients as they happen.
GraphQL subscriptions are only available for item collections on the /graphql endpoint, not for system collections.
WebSocket Endpoint
Subscriptions connect via WebSocket:
ws://your-directus-instance.com/graphql
wss://your-directus-instance.com/graphql
Use wss:// for secure connections (HTTPS sites) and ws:// for local development.
Configuration
Enable GraphQL subscriptions via WebSockets with environment variables:
Enable GraphQL Subscriptions
WEBSOCKETS_ENABLED = true
WEBSOCKETS_GRAPHQL_ENABLED = true
Authentication Modes
Configure how clients authenticate:
# Options: strict, handshake, public
WEBSOCKETS_GRAPHQL_AUTH = handshake
Authentication Modes:
strict : Clients must authenticate before connecting (via URL or headers)
handshake : Clients authenticate during connection initialization
public : No authentication required (for public data only)
Authentication Timeout
Set timeout for handshake authentication:
WEBSOCKETS_GRAPHQL_AUTH_TIMEOUT = 10000
Custom WebSocket Path
WEBSOCKETS_GRAPHQL_PATH = /graphql
Subscription Types
For each collection, Directus generates a subscription:
This subscription fires when items are created, updated, or deleted.
Basic Subscription
Subscribe to all mutations on a collection:
subscription {
articles_mutated {
key
event
data {
id
title
status
}
}
}
Response Fields:
key: The ID of the affected item
event: The mutation type (create, update, or delete)
data: The item data (null for delete events)
Filter by Event Type
Subscribe only to specific event types:
subscription {
articles_mutated ( event : "create" ) {
key
event
data {
id
title
created_at
}
}
}
Available Events:
create: Item was created
update: Item was updated
delete: Item was deleted
Subscribe to Specific Fields
Request only the fields you need:
subscription {
articles_mutated {
key
event
data {
title
status
updated_at
}
}
}
Subscribe with Relationships
Include related data in subscription updates:
subscription {
articles_mutated {
key
event
data {
id
title
author {
id
name
}
categories {
categories_id {
id
name
}
}
}
}
}
Authentication
Handshake Authentication
Authenticate during connection initialization:
import { createClient } from 'graphql-ws' ;
const client = createClient ({
url: 'wss://your-directus-instance.com/graphql' ,
connectionParams: {
access_token: 'your-access-token' ,
},
});
Strict Authentication
Authenticate via URL parameters:
const client = createClient ({
url: 'wss://your-directus-instance.com/graphql?access_token=your-token' ,
});
Client Implementation
Using graphql-ws
import { createClient } from 'graphql-ws' ;
const client = createClient ({
url: 'wss://your-directus-instance.com/graphql' ,
connectionParams: {
access_token: 'your-access-token' ,
},
});
const subscription = client . iterate ({
query: `
subscription {
articles_mutated {
key
event
data {
id
title
status
}
}
}
` ,
});
( async () => {
for await ( const result of subscription ) {
console . log ( 'Update received:' , result );
}
})();
Using Apollo Client
import { ApolloClient , InMemoryCache , split , HttpLink } from '@apollo/client' ;
import { GraphQLWsLink } from '@apollo/client/link/subscriptions' ;
import { getMainDefinition } from '@apollo/client/utilities' ;
import { createClient } from 'graphql-ws' ;
const httpLink = new HttpLink ({
uri: 'https://your-directus-instance.com/graphql' ,
headers: {
authorization: `Bearer ${ token } ` ,
},
});
const wsLink = new GraphQLWsLink (
createClient ({
url: 'wss://your-directus-instance.com/graphql' ,
connectionParams: {
access_token: token ,
},
})
);
const splitLink = split (
({ query }) => {
const definition = getMainDefinition ( query );
return (
definition . kind === 'OperationDefinition' &&
definition . operation === 'subscription'
);
},
wsLink ,
httpLink
);
const client = new ApolloClient ({
link: splitLink ,
cache: new InMemoryCache (),
});
Using the Directus SDK
import { createDirectus , graphql , realtime } from '@directus/sdk' ;
const client = createDirectus ( 'https://your-directus-instance.com' )
. with ( graphql ())
. with ( realtime ());
await client . connect ();
const { subscription } = await client . subscribe (
`
subscription {
articles_mutated {
key
event
data {
id
title
}
}
}
`
);
for await ( const message of subscription ) {
console . log ( 'Received:' , message );
}
Subscription Events
Create Event
Fired when an item is created:
{
"data" : {
"articles_mutated" : {
"key" : "abc-123" ,
"event" : "create" ,
"data" : {
"id" : "abc-123" ,
"title" : "New Article" ,
"status" : "draft"
}
}
}
}
Update Event
Fired when an item is updated:
{
"data" : {
"articles_mutated" : {
"key" : "abc-123" ,
"event" : "update" ,
"data" : {
"id" : "abc-123" ,
"title" : "Updated Article" ,
"status" : "published"
}
}
}
}
Delete Event
Fired when an item is deleted:
{
"data" : {
"articles_mutated" : {
"key" : "abc-123" ,
"event" : "delete" ,
"data" : null
}
}
}
Delete events don’t include item data, only the key (ID) of the deleted item.
Permission Handling
Subscriptions respect user permissions:
Users only receive updates for items they have read access to
If permissions change and a user loses access, they won’t receive further updates
Permission errors are silently ignored (no notification sent)
Using Variables
Use variables to make subscriptions dynamic:
subscription ArticleUpdates ( $event : String ) {
articles_mutated ( event : $event ) {
key
event
data {
id
title
status
}
}
}
Variables:
Connection Lifecycle
Connection States
Connecting : Establishing WebSocket connection
Connected : Connection established, can subscribe
Reconnecting : Lost connection, attempting to reconnect
Disconnected : Connection closed
Handling Connection Errors
import { createClient } from 'graphql-ws' ;
const client = createClient ({
url: 'wss://your-directus-instance.com/graphql' ,
connectionParams: {
access_token: token ,
},
on: {
connected : () => console . log ( 'Connected' ),
error : ( error ) => console . error ( 'Connection error:' , error ),
closed : () => console . log ( 'Connection closed' ),
},
});
Auto-Reconnection
Most GraphQL clients handle reconnection automatically. Configure retry behavior:
const client = createClient ({
url: 'wss://your-directus-instance.com/graphql' ,
retryAttempts: 10 ,
retryWait : async ( retries ) => {
await new Promise (( resolve ) =>
setTimeout ( resolve , Math . min ( 1000 * 2 ** retries , 10000 ))
);
},
});
Complete Example
Here’s a full example of using subscriptions in a React application:
import React , { useEffect , useState } from 'react' ;
import { createClient } from 'graphql-ws' ;
const client = createClient ({
url: 'wss://your-directus-instance.com/graphql' ,
connectionParams: {
access_token: 'your-token' ,
},
});
function ArticleSubscription () {
const [ articles , setArticles ] = useState ([]);
const [ updates , setUpdates ] = useState ([]);
useEffect (() => {
const subscription = client . iterate ({
query: `
subscription {
articles_mutated {
key
event
data {
id
title
status
updated_at
}
}
}
` ,
});
( async () => {
for await ( const result of subscription ) {
const { key , event , data } = result . data . articles_mutated ;
setUpdates ( prev => [
{ key , event , timestamp: new Date () },
... prev . slice ( 0 , 9 )
]);
if ( event === 'create' ) {
setArticles ( prev => [ data , ... prev ]);
} else if ( event === 'update' ) {
setArticles ( prev =>
prev . map ( article =>
article . id === key ? data : article
)
);
} else if ( event === 'delete' ) {
setArticles ( prev =>
prev . filter ( article => article . id !== key )
);
}
}
})();
return () => {
subscription . return ?.();
};
}, []);
return (
< div >
< h2 > Live Articles </ h2 >
< ul >
{ articles . map ( article => (
< li key = { article . id } >
{ article . title } - { article . status }
</ li >
)) }
</ ul >
< h3 > Recent Updates </ h3 >
< ul >
{ updates . map (( update , i ) => (
< li key = { i } >
{ update . event } - { update . key } at { update . timestamp . toLocaleTimeString () }
</ li >
)) }
</ ul >
</ div >
);
}
export default ArticleSubscription ;
Best Practices
Only Subscribe to Needed Fields
Request only the fields you need to reduce bandwidth: # Good - minimal fields
subscription {
articles_mutated {
key
event
data {
title
status
}
}
}
# Avoid - unnecessary fields
subscription {
articles_mutated {
key
event
data {
id
title
content
author { id name email bio }
created_at
updated_at
}
}
}
If you only need specific events, filter them: # Only listen for new items
subscription {
articles_mutated ( event : "create" ) {
key
data { title }
}
}
Always implement reconnection logic for production: const client = createClient ({
url: 'wss://your-instance.com/graphql' ,
retryAttempts: Infinity ,
shouldRetry : () => true ,
});
Always clean up subscriptions when components unmount: useEffect (() => {
const unsubscribe = subscribe ({ query });
return () => unsubscribe ();
}, []);
Remember that delete events don’t include data: if ( event === 'delete' ) {
// Only 'key' is available, 'data' is null
removeItem ( key );
}
Troubleshooting
Ensure WebSockets are enabled: WEBSOCKETS_ENABLED = true
WEBSOCKETS_GRAPHQL_ENABLED = true
Check your authentication mode and token: // For handshake mode
connectionParams : {
access_token : 'your-valid-token'
}
Verify:
User has read permissions for the collection
Subscription query syntax is correct
WebSocket connection is established
Increase the authentication timeout: WEBSOCKETS_GRAPHQL_AUTH_TIMEOUT = 30000
Next Steps
GraphQL Queries Learn how to query your data
GraphQL Mutations Create, update, and delete data