State Management
Learn how to manage state within your Motia.dev workflows for persistent data and cross-step communication.
State management is fundamental to building robust and dynamic workflows in Motia.dev. Our system is designed to be powerful yet simple, providing you with everything you need to maintain state across your flows and steps:
β¨ Zero Configuration (Default): In-memory storage out of the box for quick setup.
π Flexible Storage Options: Choose from Memory, File, and Redis adapters to suit your persistence needs.
π§Ή Automatic State Cleanup: Optional Time-To-Live (TTL) support for automatic state expiration (Redis).
π Built-in Isolation: Each flow execution can use its own isolated state, ensuring data separation and security.
Core Concepts: State Manager Methods
The state
object, accessible within your step handlers via the ctx
context, provides the following methods for state management:
Method | Parameters | Return Type | Description |
---|---|---|---|
get | scope: string, key: string | Promise<T | null> | Retrieves a value associated with the given key and scope from the state store. Returns null if the key is not found. The type T is inferred based on how you use the returned value. |
set | scope: string, key: string, value: T | Promise<void> | Stores a value associated with the given key and scope in the state store. The type T can be any serializable JavaScript/JSON value. |
delete | scope: string, key: string | Promise<void> | Removes the key-value pair associated with the given key and scope from the state store. |
clear | scope: string | Promise<void> | Removes all state data associated with the provided scope . This is useful for cleaning up state for a specific scope. |
cleanup | (None) | Promise<void> | Performs periodic maintenance tasks, such as removing expired state data (TTL cleanup). The actual implementation depends on the configured state adapter. |
Important: State manager methods (get
, set
, delete
, clear
) require a scope
string as the first parameter. While in most cases, you will use the traceId
(automatically provided in ctx.traceId
) as the scope to ensure flow-level isolation, you can technically use any string value as the scope to group and manage state data as needed. Using traceId
is the recommended and most common practice for flow-isolated state.
State Scope and Isolation
Each flow execution in Motia.dev is assigned a unique traceId
(a UUID). Using this traceId
as the scope for state management provides automatic isolation, ensuring: (Revised to clarify traceId
as scope)
Feature | Description |
---|---|
Isolation | Each flow execution operates within its own isolated state space when using traceId as the scope. |
Boundaries | Clear separation of state data between different flow executions when scoped by traceId , preventing interference. |
Cleanup | State data scoped by traceId can be easily cleared using state.clear(traceId) . |
State Structure Example
State data is stored as key-value pairs, namespaced under a scope string. When using traceId
as the scope, the internal structure might look like this:
Info: You can access the
state
manager within any step through thectx
(context) argument, which is automatically injected into your step handler. WhiletraceId
fromctx.traceId
is the recommended scope for flow isolation, remember that you can use any string as the scope parameter instate
methods for more advanced state management scenarios.
Using State in Steps
Debugging
Inspecting State
State is only available during runtime in the Node.js process memory. You cannot inspect memory state directly outside of a running step execution. Use logging within your steps to output state values for debugging purposes.
Best Practices
Namespacing
Use dot notation to organize related state data hierarchically:
Type Safety
Define types for your state data to ensure consistency:
Cleanup
Always clean up state when you're done with it:
Performance Considerations
Consideration | Description |
---|---|
Batch Operations | Group related state updates and use atomic operations when possible |
State Size | Keep state data minimal and consider access patterns |
TTL Management | Set appropriate TTLs based on flow duration and error recovery needs |
Custom State Adapters
Storage Adapters
Motia.dev offers three built-in storage adapters:
- π File (Default): Persists state to a JSON file in your project (
.motia/motia.state.json
). No configuration needed for basic use. - πΎ Memory: Stores state in-memory. Fastest option, but state is not persistent across server restarts. Useful for development and non-critical data.
- β‘ Redis: Leverages Redis for persistent and scalable state storage. Ideal for production environments and flows requiring high availability and data durability.
To configure a different state adapter, modify the config.yml
file in your project root:
File Adapter (Default)
Default, no configuration required, state is stored into .motia/motia.state.json in your project root
Memory Adapter
Warning: Memory Adapter State is stored in-memory and will be lost when the Motia.dev server restarts. Suitable for development and testing.
Redis Adapter
Info: Redis Adapter Recommended for production environments. Requires a running Redis server. The
ttl
(Time-To-Live) option is available to automatically expire state data after a specified number of seconds, helping to manage Redis storage.
Common Issues
Issue | Troubleshooting Steps |
---|---|
State Not Found | - Verify state adapter configuration\n- Check TTL expiration (Redis)\n- Ensure file permissions (File adapter)\n- Ensure correct traceId is being used in state.get(traceId, key) calls. |
Persistence | - Memory adapter: State is lost on process restart\n- File adapter: Check file write permissions\n- Redis: Verify connection and persistence settings |
Concurrent Access | - Memory/File: Limited concurrent flow support\n- Redis: Use atomic operations and implement retry logic |