# Clarification needed: Assistant config vs context and graph initialization

**URL:** <https://forum.langchain.com/t/clarification-needed-assistant-config-vs-context-and-graph-initialization/3902>\
**Category:** LangGraph\
**Tags:** self-hosted, python-help\
**Created:** [June 11, 2026, 8:30am UTC](https://forum.langchain.com/t/clarification-needed-assistant-config-vs-context-and-graph-initialization/3902 "2026-06-11T08:30:41Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![gdrouet](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.langchain.com/gdrouet/32/2429_2.png) [@gdrouet](https://forum.langchain.com/u/gdrouet)\
**Post date:** [June 11, 2026, 8:30am UTC](https://forum.langchain.com/t/clarification-needed-assistant-config-vs-context-and-graph-initialization/3902/1 "2026-06-11T08:30:41Z")

</div>

Hi everyone,

I’m a bit confused about the respective roles of `config` and `context` when working with assistants in LangGraph Platform.

When creating an assistant through the API, I see both fields:

```auto
{
  "graph_id": "my_graph",
  "config": {},
  "context": {}
}

```

From the documentation and examples, it seems that assistant-specific values are typically accessed through `runtime.context`, using a `context_schema`.

However, this leaves me with a few questions:

1. What is the intended purpose of the assistant-level `config` field?
2. How does it differ from `context` in practice?
3. Can either `config` or `context` be accessed during graph initialization (inside the graph factory / `make_graph()` function), or are they only available at runtime?
4. If I want to customize the graph structure based on assistant settings, what is the recommended approach?

My current understanding is:

- Neither `context` nor assistant configuration are available when the graph is being constructed.
- Graph customization should therefore happen at runtime rather than during graph compilation.

Is that correct, or am I missing something?

Thanks!

---

<div class="post-metadata">

**Author:** ![pawel-twardziak](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.langchain.com/pawel-twardziak/32/960_2.png) [@pawel-twardziak](https://forum.langchain.com/u/pawel-twardziak)\
**Post date:** [June 11, 2026, 11:13am UTC](https://forum.langchain.com/t/clarification-needed-assistant-config-vs-context-and-graph-initialization/3902/2 "2026-06-11T11:13:23Z")

</div>

Hi @gdrouet

great question. It’s been confusing to me for a long time though, I think I can explain it this way:

short: `config` is the legacy/runtime-plumbing channel (`RunnableConfig`: `configurable`, `tags`, `recursion_limit`), `context` is its typed v0.6+ successor for user-defined values, and - contrary to your current understanding - both can be available during graph construction if you register a graph factory instead of a pre-compiled graph.

1. What is the assistant-level `config` field for?

It is a persisted `RunnableConfig` fragment. Per the [Create Assistant API reference](https://docs.langchain.com/langsmith/agent-server-api/assistants/create-assistant), assistant `config` has exactly three keys:

- `configurable: dict` - arbitrary key/value configuration (the pre-v0.6 way to parameterize a graph)
- `tags: string[]` - tracing tags applied to every run of this assistant
- `recursion_limit: int` - execution knob for the Pregel loop

When a run is created, the server merges the assistant’s `config` into the run’s `RunnableConfig`. In the dev server (`langgraph_runtime_inmem/ops.py`, `Runs.put`) the run config is built as:

```python
"config": Runs._merge_jsonb(
    assistant["config"], # assistant-level config
    config, # run-level config (wins on conflicts)
    {"configurable": configurable}, # assistant -> thread -> run configurable
    {"metadata": merged_metadata},
),

```

and the `configurable` dict itself is merged as `assistant.configurable -> thread.configurable -> run.configurable -> {run_id, thread_id, graph_id, assistant_id, user_id}` - later sources win, so run-level values override assistant-level values.

So the intended purposes of assistant `config` today are:

- carrying values for graphs that still read `config["configurable"]` (the pre-0.6 pattern - still fully supported for backward compatibility)
- pinning execution knobs that `context` cannot express: `tags` and `recursion_limit`
- feeding the graph-factory path (see Q3)

**2. How does it differ from `context` in practice?**

`context` is the typed replacement for user-defined `config["configurable"]` values, introduced in LangGraph v0.6:

- You declare a `context_schema` on the graph (`StateGraph(State, context_schema=Context)` / `create_agent(..., context_schema=Context)`). In the langgraph source: `libs/langgraph/langgraph/graph/state.py` - `context_schema` parameter; the old `config_schema` parameter is deprecated since v0.6.0 with removal planned in v2.0.0
- It travels as a separate channel, not inside `config`: `graph.invoke(input, context=...)` (`libs/langgraph/langgraph/pregel/main.py`, `invoke(..., context: ContextT | None = None)`), is coerced to your dataclass/Pydantic/TypedDict schema (`_coerce_context`), and is exposed to nodes/tools/middleware as `runtime.context` on the frozen `Runtime` dataclass (`libs/langgraph/langgraph/runtime.py`). Internally the `Runtime` rides along in `config["configurable"]["__pregel_runtime"]`, which is why the two systems interoperate
- On the assistant object, `config` and `context` are stored as two separate fields (`AssistantBase` in `libs/sdk-py/langgraph_sdk/schema.py`: `config: Config`, `context: Context`; the latter was added in SDK v0.6.0 - “Static context to add to the assistant”)
- At run creation the server merges them independently: `"context": Runs._merge_jsonb(assistant.get("context", {}), kwargs.get("context", {}))` - run-level context wins. The merged context is then passed to the graph’s `astream/ainvoke` as the `context` argument (the server even filters it against your graph’s context JSON schema first - `_filter_context_by_schema` in `langgraph_api/stream.py`)

Practical rule of thumb:

| | `config` | `context` |
| --- | --- | --- |
| Typing | untyped `configurable` dict | validated against `context_schema` |
| Access in graph code | `config["configurable"]["x"]` (legacy) | `runtime.context.x` (current) |
| Extra knobs | `tags`, `recursion_limit` | - |
| Status | supported, legacy for user values | recommended since v0.6 |
| Merge at run time | assistant → thread → run (run wins) | assistant → run (run wins) |

The docs ([Assistants](https://docs.langchain.com/langsmith/assistants#configuration), [configuration how-to](https://docs.langchain.com/langsmith/configuration-cloud#understand-assistant-configuration)) now describe assistants almost entirely in terms of `context` - that is the recommended channel for “assistant settings” your nodes read. The [v1 migration guide](https://docs.langchain.com/oss/python/migrate/langchain-v1#runtime-context) explicitly notes the old `config["configurable"]` pattern still works but `context` is recommended.

**3. Can `config`/`context` be accessed during graph initialization?**

Yes - if you register a graph factory. This is the part your current understanding misses.

If your `langgraph.json` points at a callable instead of a compiled graph (`"my_graph": "./graph.py:make_graph"`), the server rebuilds the graph via that factory every time it needs it. From `langgraph_api/graph.py` (installed server, v0.4.20):

```python
FACTORY_ACCEPTS_CONFIG[graph_id] = len(inspect.signature(graph).parameters) > 0
...
value = value(config) if factory_accepts_config(value, graph_id) else value()

```

and from `langgraph_api/stream.py` - when a run executes, the factory receives the merged run config (assistant config → run config, including the merged `configurable`):

```python
context = kwargs.pop("context", None)
config = cast(RunnableConfig, kwargs.pop("config")) # already merged with assistant config
graph = await stack.enter_async_context(
    get_graph(configurable["graph_id"], config, ...)
)

```

So inside `make_graph(config: RunnableConfig)` you can read `config["configurable"]["my_setting"]` and it will reflect the assistant’s `configurable` (overridden by run-level values if provided). Note the factory is also invoked for non-run endpoints (assistant schemas, subgraphs, state reads) - e.g. `langgraph_api/api/assistants.py` loads `assistant["config"]` and calls `get_graph(graph_id, config)` for the schema endpoints - so assistant `config` is available there too.

`context` in the factory: on recent agent-server versions the factory can declare a second parameter, `runtime: ServerRuntime` ([Rebuild graph at runtime](https://docs.langchain.com/langsmith/graph-rebuild); `langgraph_sdk/runtime.py` in the langgraph repo). The server inspects type hints and injects it. `ServerRuntime` exposes:

- `access_context` - why the factory is being called (`"threads.create_run"`, `"assistants.read"`, `"threads.read"`, …),
- `execution_runtime` - non-`None` only when actually executing a run, and it carries `context` (the merged assistant → run context), the authenticated `user`, and the `store`.

```python
async def make_graph(config: RunnableConfig, runtime: ServerRuntime):
    if ert := runtime.execution_runtime:
        ctx = ert.context # merged assistant/run context - execution paths only
    ...

```

(The 2-arg factory shape is exercised end-to-end in the langgraph repo’s integration fixture `libs/sdk-py/integration/graph/factory_graph.py`.) On older servers (1-arg factory), `context` is not passed to the factory at all - it is only handed to the graph at invoke time - so on those versions only `config["configurable"]` is usable for construction-time decisions.

If you export a pre-compiled graph (no factory), then your statement is correct: the module is imported once at server startup and nothing assistant-specific exists at compile time.

---

<div class="post-metadata">

**Author:** ![pawel-twardziak](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.langchain.com/pawel-twardziak/32/960_2.png) [@pawel-twardziak](https://forum.langchain.com/u/pawel-twardziak)\
**Post date:** [June 11, 2026, 11:17am UTC](https://forum.langchain.com/t/clarification-needed-assistant-config-vs-context-and-graph-initialization/3902/3 "2026-06-11T11:17:51Z")

</div>

**Customizing the graph per assistant**

In order of preference:

1. keep one topology, vary behavior at runtime. Read `runtime.context` in nodes/conditional edges to pick models, prompts, tools, and routing. This is the pattern the docs push for assistants ([configuration how-to](https://docs.langchain.com/langsmith/configuration-cloud)) and it works with checkpointing, schema endpoints, and Studio with zero surprises. Conditional edges mean “different structure per run” rarely requires actually different graphs
2. if construction itself must differ (e.g. tools discovered from an MCP server, per-tenant node sets), use a graph factory keyed off `config["configurable"]` - available on both execution and read paths - and/or `runtime.execution_runtime` for execution-only resources. Two caveats from the [graph-rebuild docs](https://docs.langchain.com/langsmith/graph-rebuild):
  - the factory runs on every request that needs the graph (runs, state reads, schema fetches), so keep it fast
  - the returned graph should keep the same topology (nodes, edges, state schema) across access contexts - use `execution_runtime` to conditionally wire expensive resources, not to reshape the graph, otherwise schema/state endpoints can disagree with what actually ran

3. if you truly need different topologies, register them as separate graphs in `langgraph.json` and create assistants against different `graph_id`s

**So**

- “neither `context` nor assistant configuration are available when the graph is being constructed” - incorrect for factories: assistant `config.configurable` is passed to `make_graph(config)` (merged with run config on execution paths), and merged `context` is available via `ServerRuntime.execution_runtime.context` on recent server versions (execution paths only). Correct only for pre-compiled graph exports
- “graph customization should therefore happen at runtime rather than during graph compilation” - right default, but as a recommendation, not a hard constraint: runtime branching via `runtime.context` first, graph factory when construction genuinely depends on assistant settings
