← Blog

Claude Function Calling: Parallel Tool Execution Guide

2026-11-09 · 5 min read · SubToAPI Team

When Claude decides it needs to call tools to answer a request, it doesn't always limit itself to one tool at a time. If the model determines that multiple independent tool calls are needed to complete a task, it can return several tool_use blocks in a single response, and your job as the integrator is to execute them — ideally in parallel — and send all the results back together.

This is Claude's native parallel tool execution behavior, and it's distinct from forcing parallelism yourself by firing off multiple separate API requests. Claude decides when parallel calls make sense (e.g., "get the weather in Paris and Tokyo" naturally produces two independent get_weather calls), and your application layer is responsible for running those calls concurrently and returning a single tool_result message containing all outputs, matched by tool_use_id.

How Claude Returns Multiple Tool Calls

When a user prompt implies independent, non-sequential actions, Claude's response can include more than one tool_use content block in the same message. For example:

{
  "role": "assistant",
  "content": [
    {
      "type": "tool_use",
      "id": "toolu_01A",
      "name": "get_weather",
      "input": { "city": "Paris" }
    },
    {
      "type": "tool_use",
      "id": "toolu_01B",
      "name": "get_weather",
      "input": { "city": "Tokyo" }
    }
  ]
}

Both blocks arrive in the same assistant turn. There's no separate "parallel mode" flag to enable — this happens automatically based on how the model interprets the task. Your code needs to be ready to loop over an array of tool_use blocks instead of assuming there's exactly one.

Executing Tool Calls Concurrently

The performance win comes from how you handle the array of tool calls, not from anything Claude does differently. If you execute tool calls sequentially with await in a loop, you lose the benefit entirely. Instead, collect all tool_use blocks and run them concurrently:

const toolUseBlocks = response.content.filter(
  (block) => block.type === "tool_use"
);

const results = await Promise.all(
  toolUseBlocks.map(async (block) => {
    const output = await executeTool(block.name, block.input);
    return {
      type: "tool_result",
      tool_use_id: block.id,
      content: JSON.stringify(output),
    };
  })
);

Then send all results back in a single user message with multiple tool_result blocks:

const followUp = await client.messages.create({
  model: "claude-sonnet-4-5",
  max_tokens: 1024,
  messages: [
    ...previousMessages,
    { role: "assistant", content: response.content },
    { role: "user", content: results },
  ],
  tools,
});

This matters most when tool calls hit slow external resources — databases, third-party APIs, file systems. Two calls each taking 400ms run in 800ms sequentially but roughly 400ms in parallel. With five or six independent tool calls (common in agentic workflows that fan out across multiple data sources), the difference compounds fast.

Common Mistakes

Assuming only one tool call per response. Code that does response.content[0] and extracts a single tool call will silently drop additional calls. Always filter and iterate over all tool_use blocks.

Matching results by array position instead of tool_use_id. Claude doesn't guarantee the order in which it would process results, and your own execution order may differ due to async timing. Always key results explicitly by tool_use_id.

Executing in sequence by accident. A for...of loop with await inside looks correct but runs calls one after another. Use Promise.all (or Promise.allSettled if you want partial failures to not block the rest).

Not handling partial failures. If one of three parallel tool calls throws an error, decide whether to return an error string in that specific tool_result block (letting Claude reason about it) or abort the whole turn. Returning a tool_result with an error message is usually better than crashing, since Claude can often recover or ask a follow-up question.

Ignoring tool_choice settings. If you want to force or restrict tool use, Claude's API supports tool_choice parameters (auto, any, tool, or none). Parallel calls primarily occur under auto, which is the default and lets the model decide both whether and how many tools to invoke.

When Parallel Execution Doesn't Apply

Not every multi-step task is parallelizable. If tool B needs the output of tool A, Claude will typically call A first, wait for the result, then call B in a subsequent turn — this is sequential tool use, not parallel. Parallel calls only happen when the model identifies that the calls are independent of each other. You don't need to detect this distinction yourself; just write your execution loop generically enough to handle one tool call or several without special-casing either path.

Simplifying the Infrastructure Layer

Handling concurrent tool execution, retries, and result formatting is logic you write once in your own code regardless of which provider sits behind it. But if you're exposing Claude-backed tool use to other services or teammates as an internal API, you still need request authentication, usage tracking per caller, and streaming support layered on top.

That's the gap SubToAPI fills: it converts your existing Claude access into a standard HTTPS API with application-level sub_live_... keys, so you can call /docs/tools to use function calling, /docs/streaming for streamed responses, and /docs/messages for standard chat completions — all from one dashboard with per-key usage metadata and team seats. You still write the parallel execution loop in your own backend; SubToAPI just gives you the authenticated endpoint and visibility into who's calling what. Plans start at the Solo tier (€9/mo), with Team (€19/seat) and Scale (€49/seat) options and a free trial at /signup. Full setup is in /docs/quickstart.

Questions

Does Claude execute tool calls in parallel on Anthropic's servers? No. Claude only decides which tools to call and returns multiple tool_use blocks in one response. The actual execution — including whether it's concurrent — happens in your application code.

How do I know if Claude returned multiple tool calls? Check response.content for more than one block with type: "tool_use". Don't assume a single tool call; always filter the array before processing.

What happens if I execute parallel tool calls sequentially by mistake? Nothing breaks functionally — Claude still gets correct results — but you lose the latency benefit. Each tool call's wait time stacks instead of overlapping, which slows down agentic workflows with multiple independent calls.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →