# What is different between using DynamicStructuredTool vs tool()?

**URL:** <https://forum.langchain.com/t/what-is-different-between-using-dynamicstructuredtool-vs-tool/2514>\
**Category:** LangChain\
**Tags:** js-help\
**Created:** [December 15, 2025, 8:17am UTC](https://forum.langchain.com/t/what-is-different-between-using-dynamicstructuredtool-vs-tool/2514 "2025-12-15T08:17:13Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![carefreelife98](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.langchain.com/carefreelife98/32/1696_2.png) [@carefreelife98](https://forum.langchain.com/u/carefreelife98)\
**Post date:** [December 15, 2025, 8:17am UTC](https://forum.langchain.com/t/what-is-different-between-using-dynamicstructuredtool-vs-tool/2514/1 "2025-12-15T08:17:13Z")

</div>

I would like to standardize the approach for creating and utilizing tools within our project. Currently, some tools are implemented using `DynamicStructuredTool` directly, while others employ the `tool()` function to manually return `Command` objects. Could you please advise which approach would be more suitable for long-term project maintainability and scalability?

---

<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:** [December 15, 2025, 11:20am UTC](https://forum.langchain.com/t/what-is-different-between-using-dynamicstructuredtool-vs-tool/2514/2 "2025-12-15T11:20:05Z")

</div>

hi @carefreelife98

given those files [index.ts](https://github.com/langchain-ai/langchainjs/blob/main/libs/langchain-core/src/tools/index.ts), [types.ts](https://github.com/langchain-ai/langchainjs/blob/main/libs/langchain-core/src/tools/types.ts), we could state this:

**TL;DR:** In LangChain JS, `tool()` is a higher‑level factory that _builds_ `DynamicStructuredTool`/`DynamicTool` for you and wires in newer runtime features (state, context, interrupts, cancellation, etc.). For a long‑lived codebase, **standardize on `tool()` for almost everything** and only reach for `DynamicStructuredTool` when you explicitly need low‑level control or custom subclasses.

### What is actually different?

**1. `DynamicStructuredTool` is the low‑level class.**

- You instantiate it directly:
  - `new DynamicStructuredTool({ name, description, schema, func, ... })`.
  - `func(input, runManager?, config?)` gets called after the schema has been applied.

- It’s just a `StructuredToolInterface` implementation: schema validation + `_call` wrapper, with no extra opinions.
- Source: see `DynamicStructuredTool` in `index.ts` (around lines 450–511).

**2. `tool()` is a convenience factory with extra plumbing.**

- `tool()` returns either a `DynamicTool` (string input) or `DynamicStructuredTool` (object/JSON schema input) based on the schema you pass.
- It accepts functions of the form:
  - `async (input, runtime: ToolRuntime) => ...` **or**
  - `async (input, config: ToolRunnableConfig) => ...`.

- Internally (`index.ts` lines ~744–845 and `types.ts` lines ~448–548):
  - Wraps your function in the LangChain/LangGraph execution context via `AsyncLocalStorageProviderSingleton`.
  - Handles `AbortSignal` cancellation for tools.
  - Injects `ToolRuntime` (state, context, store, writer, toolCallId, config) when used with LangGraph.
  - Ensures callbacks / metadata / config are propagated consistently.

- This is the API that current LangChain + LangGraph docs push for defining tools, e.g. the custom tools and interrupts examples ([Interrupts - Docs by LangChain](https://docs.langchain.com/oss/javascript/langgraph/interrupts#interrupts-in-tools)).

**3. For the LLM, both look the same.**

- Both approaches ultimately expose the same things to the model: `name`, `description`, and an argument `schema`.
- The difference is **ergonomics and integration with the broader runtime** , not what the model sees.

### About returning `Command` objects

**Returning `Command` is orthogonal to `DynamicStructuredTool` vs `tool()`.**

- A tool’s return type in JS is largely unconstrained (`ToolOutputType`), so you can return a `Command` from either a manually created `DynamicStructuredTool` or a `tool()`-created tool.
- LangGraph’s runtime special‑cases `Command` in graph nodes; it doesn’t care whether the underlying tool was made via `new DynamicStructuredTool(...)` or `tool(...)`.
- Where `tool()` _does_ help is giving you the `ToolRuntime` (state, context, store, writer), which is extremely useful in non-trivial graphs that use `Command` to orchestrate flow.

### Recommendation for maintainability & scalability

**I would standardize on `tool()` for project code.**

- **Pros:**
  - Less boilerplate; consistent pattern: `const myTool = tool(async (input, runtime) => { ... }, { name, description, schema })`.
  - Automatically gains new LangChain/LangGraph runtime features (state injection, context, better cancellation, streaming via `runtime.writer`, etc.) without you changing every tool.
  - Easier onboarding: new engineers learn one idiomatic pattern that matches the official docs.

- **Use `DynamicStructuredTool` directly only when:**
  - You need a custom subclass or to override parts of `StructuredTool`/`invoke`.
  - You are building a lower‑level library that wants fine‑grained control over callback plumbing or config types.
  - You are porting/mirroring legacy code that already works at the `DynamicStructuredTool` level and you have a strong reason not to touch it.

In a typical app that uses LangChain + LangGraph and returns `Command` objects from tools, the most future‑proof, maintainable approach is: **define all new tools with `tool()` and gradually migrate existing `DynamicStructuredTool` usages to that helper unless you have a concrete need for the low‑level API.**

---

<div class="post-metadata">

**Author:** ![carefreelife98](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.langchain.com/carefreelife98/32/1696_2.png) [@carefreelife98](https://forum.langchain.com/u/carefreelife98)\
**Post date:** [December 15, 2025, 11:46am UTC](https://forum.langchain.com/t/what-is-different-between-using-dynamicstructuredtool-vs-tool/2514/3 "2025-12-15T11:46:54Z")

</div>

Hi @pawel-twardziak ,  
thank you so much for taking the time to write such a detailed and thoughtful explanation. This was incredibly helpful — it clarified not just the _what_, but the _why_ behind `tool()` vs `DynamicStructuredTool`, especially around runtime integration and long-term maintainability.

Your breakdown of the internal plumbing (AsyncLocalStorage, cancellation, ToolRuntime injection, etc.) really helped me connect the docs with the actual implementation, and the recommendation section gives a very clear direction for how to structure a real production codebase. It saved me a lot of trial-and-error.

I really appreciate the depth and clarity here. Thanks again — this was a big help! 🙂
