tl  tr
  Home | Tutorials | Articles | Videos | Products | Tools | Search
Interviews | Open Source | Tag Cloud | Follow Us | Bookmark | Contact   
 Agentic AI > LangGraph > LangGraph State and TypedDict Reducers

LangGraph State and TypedDict Reducers

Author: Venkata Sudhakar

In LangGraph every node reads from and writes to a shared State object. The State is a TypedDict - a Python typed dictionary - and its schema defines exactly what data flows through the agent. When a node returns a dict, LangGraph merges it into the current state. By default a returned value replaces the existing field value. But for fields like message history where you want to append rather than replace, you use an Annotated type with a reducer function to control the merge.

The most common reducer is operator.add, which concatenates lists. When you declare Annotated[list, operator.add], every node that returns that field has its value appended to the existing list rather than replacing it. This is how LangGraph handles message history - each node adds its messages to the growing conversation. You can also write custom reducer functions for deduplication or priority-based merging. Understanding reducers is essential for building correct multi-node agents.

The below example shows a two-node graph demonstrating the difference between the default replace behaviour and the list-append reducer.


Running the graph to see reducer behaviour,


It gives the following output,

node_a sees 1 messages, status = initial
node_b sees 2 messages, status = node_a_done

Final state:
messages count: 3
messages: ["Start the pipeline", "Response from node A", "Response from node B"]
status: node_b_done          <- replaced each time, only last value survives
steps_taken: ["node_a", "node_b"]  <- appended by both nodes, full history kept

# Without operator.add on messages:
# node_b would only see node_a return value, not the original human message
# The full conversation history would be lost

Custom reducer ensures no URL is recorded twice,

# node_a returns: {"visited_urls": ["https://site.com/page1", "https://site.com/page2"]}
# node_b returns: {"visited_urls": ["https://site.com/page2", "https://site.com/page3"]}
# dedupe_union result: ["https://site.com/page1", "https://site.com/page2", "https://site.com/page3"]
# page2 is not duplicated even though both nodes returned it

Reducer selection guide: use operator.add for message history, log lists, and any field that should accumulate across nodes. Use no reducer (default replace) for the current task, current status, or any single-value field that each node updates to a new value. Use a custom reducer when you need deduplication, max/min selection, or merging complex objects. Getting reducers right is the most important design decision in a multi-node LangGraph agent.


 
  


  
bl  br