LangGraph state management patterns. Use when designing workflow state schemas, using TypedDict vs Pydantic, implementing accumulating state with Annotated operators, or managing shared state across nodes.
View on GitHubFebruary 4, 2026
Select agents to install to:
npx add-skill https://github.com/yonatangross/skillforge-claude-plugin/blob/main/plugins/ork/skills/langgraph-state/SKILL.md -a claude-code --skill langgraph-stateInstallation paths:
.claude/skills/langgraph-state/# LangGraph State Management
Design and manage state schemas for LangGraph workflows.
## TypedDict Approach (Simple)
```python
from typing import TypedDict, Annotated
from operator import add
class WorkflowState(TypedDict):
input: str
output: str
agent_responses: Annotated[list[dict], add] # Accumulates
metadata: dict
```
## MessagesState Pattern (2026 Best Practice)
```python
from langgraph.graph import MessagesState
from langgraph.graph.message import add_messages
from typing import Annotated
# Option 1: Use built-in MessagesState (recommended)
class AgentState(MessagesState):
"""Extends MessagesState with custom fields."""
user_id: str
context: dict
# Option 2: Define messages manually with add_messages reducer
class CustomState(TypedDict):
messages: Annotated[list, add_messages] # Smart append/update by ID
metadata: dict
```
**Why `add_messages` matters:**
- Appends new messages (doesn't overwrite)
- Updates existing messages by ID
- Handles message deduplication automatically
> **Note**: `MessageGraph` is deprecated in LangGraph v1.0.0. Use `StateGraph` with a `messages` key instead.
## Pydantic Approach (Validation)
```python
from pydantic import BaseModel, Field
class WorkflowState(BaseModel):
input: str = Field(description="User input")
output: str = ""
agent_responses: list[dict] = Field(default_factory=list)
def add_response(self, agent: str, result: str):
self.agent_responses.append({"agent": agent, "result": result})
```
## Accumulating State Pattern
```python
from typing import Annotated
from operator import add
class AnalysisState(TypedDict):
url: str
raw_content: str
# Accumulate agent outputs
findings: Annotated[list[Finding], add]
embeddings: Annotated[list[Embedding], add]
# Control flow
current_agent: str
agents_completed: list[str]
quality_passed: bool
```
**Key Pattern: `Annotated[list[T], add]`**
- Without `add`: Each node repla