Backward Compatibility
Status: ACTIVE (pulled from docs.langchain.com) Source: https://docs.langchain.com/oss/python/langgraph/backward-compatibility Timestamp: 2026-05-11
Update LangGraph graph code in production without breaking in-flight runs. LangGraph applies the latest graph immediately to every thread -- both new and resuming.
Three Categories of Compatibility Issues
1. Technical Compatibility
Equivalent to API breaking changes. Common breakages:
- Renaming or removing a node while threads are paused at it
- Renaming or removing a State key that older checkpoints contain
- Tightening a State field (making optional required, narrowing types)
Recommended Patterns
- Add new state fields as
NotRequired(orOptional[...] = None):
class State(TypedDict):
messages: list
summary: NotRequired[str] # NEW - old checkpoints still valid
- Treat removals as deprecations -- keep field defined for one drain cycle
- Rename through add-then-remove (dual-write during deprecation window)
- Keep node functions tolerant of unknown keys
- Use
get_stateand time travel to spot-check existing threads in staging
Detecting In-Flight Threads
- LangSmith Deployment: Thread search by status (
idle,busy,interrupted,error) - Anywhere LangGraph runs: LangSmith tracing monitors node entry/exit
- Known thread_id:
graph.get_state(config)andget_state_history(config)
2. Business Compatibility
When behavior changes should NOT apply to threads started under old logic. Solution: record behavioral version on state at thread start:
class State(TypedDict):
request: str
flow_version: NotRequired[int]
response: NotRequired[str]
def intake(state: State) -> dict:
# New threads get current version; existing threads keep saved value
return {"flow_version": state.get("flow_version", 2)}
def after_triage(state: State) -> str:
if state.get("flow_version", 1) >= 2:
return "policy_check" # New path
return "respond" # Old path
3. Non-Determinism (Functional API only)
Functional API replays entrypoint body on resume. Two kinds of changes break this:
- Adding/removing/reordering
@taskorinterrupt()calls before the resume point - Introducing non-deterministic operations outside
@task(time, random, network)
Safe options: let in-flight runs drain before deploying, wrap new logic in @task, or register new entrypoint under new graph name.
Graph Migrations Summary
- Finished threads: full topology changes supported
- Interrupted threads: all changes except renaming/removing the paused node
- State keys: adding/removing fully compatible
- Renamed keys: lose saved state in existing threads