Files
motia/bitbylaw/.cursor/rules/motia/state-management.mdc
2025-10-19 14:57:07 +00:00

137 lines
4.2 KiB
Plaintext

---
description: Managing state across Steps
globs: steps/**/*.step.ts,steps/**/*.step.js,steps/**/*_step.py
alwaysApply: false
---
# State Management
State Management is a core concept in Motia. It's used to store data across Steps.
They can be stored across different workflows.
If we want to trigger Event Steps, we can add data to the emit call, which can be used later in the Event Step execution. But this is limited and can't store too much data,
that's why we need to use the State Management to store data across Steps.
## Use-cases
**When State Management is recommended:**
- Pulling data from an external source, like an API, and storing it in the state, then triggering an Event Step to process the data.
- Storing data that needs to be used later in the workflow.
- Can be used for caching layer, like caching the result of an API call that usually can take a few seconds to complete and doesn't change very often.
**When another solution can be better suited:**
- Storing persistent user data: it's preferred to use a database like Postgres or MongoDB to store user data.
- Storing file data like Base64 encoded images, PDFs, etc: it's preferred to use a storage solution like S3, etc.
## StateManager Interface
The StateManager interface is available in the context of all step handlers. The methods work identically across TypeScript/JavaScript and Python.
```typescript
type InternalStateManager = {
/**
* Retrieves a single item from the state
*
* @param groupId - The group id of the state
* @param key - The key of the item to get
* @returns The item or null if it doesn't exist
*/
get<T>(groupId: string, key: string): Promise<T | null>
/**
* Sets a single item in the state
*
* @param groupId - The group id of the state
* @param key - The key of the item to set
* @param value - The value of the item to set
* @returns The item
*/
set<T>(groupId: string, key: string, value: T): Promise<T>
/**
* Deletes a single item from the state
*
* @param groupId - The group id of the state
* @param key - The key of the item to delete
* @returns The item or null if it doesn't exist
*/
delete<T>(groupId: string, key: string): Promise<T | null>
/**
* Retrieves a group of items from the state
*
* @param groupId - The group id of the state
* @returns A list with all the items in the group
*/
getGroup<T>(groupId: string): Promise<T[]>
/**
* Clears a group of items from the state
*
* @param groupId - The group id of the state
*/
clear(groupId: string): Promise<void>
}
```
## Usage Examples
### TypeScript/JavaScript Example
```typescript
export const handler: Handlers['ProcessOrder'] = async (input, { state, logger }) => {
// Store an order
const order = {
id: input.orderId,
status: 'processing',
createdAt: new Date().toISOString()
};
await state.set('orders', input.orderId, order);
// Retrieve an order
const savedOrder = await state.get('orders', input.orderId);
logger.info('Order retrieved', { savedOrder });
// Get all orders
const allOrders = await state.getGroup('orders');
logger.info('Total orders', { count: allOrders.length });
// Update order status
order.status = 'completed';
await state.set('orders', input.orderId, order);
// Delete an order (if needed)
// await state.delete('orders', input.orderId);
};
```
### Python Example
```python
async def handler(input_data, context):
# Store an order
order = {
"id": input_data.get("order_id"),
"status": "processing",
"created_at": datetime.now().isoformat()
}
await context.state.set("orders", input_data.get("order_id"), order)
# Retrieve an order
saved_order = await context.state.get("orders", input_data.get("order_id"))
context.logger.info("Order retrieved", {"saved_order": saved_order})
# Get all orders
all_orders = await context.state.get_group("orders")
context.logger.info("Total orders", {"count": len(all_orders)})
# Update order status
order["status"] = "completed"
await context.state.set("orders", input_data.get("order_id"), order)
# Delete an order (if needed)
# await context.state.delete("orders", input_data.get("order_id"))
```