Extended thinking is one of those Claude API features that sounds like marketing until you use it on a genuinely hard problem. Per Anthropic's documentation, when you enable it, Claude gets a dedicated internal token budget to reason step by step before producing its final response. The reasoning doesn't appear in your output β it's a private scratchpad that improves what you do get back. Extended thinking was introduced with Claude 3.7 Sonnet in early 2025 and is available on current Claude models.
As a .NET/Angular developer who uses Claude Code for development work, extended thinking is what I'd reach for on the problems where standard prompts produce confident-sounding answers that fall apart under scrutiny: architecture trade-off analysis, dependency conflict resolution, reasoning over large code context. Here's exactly how the API works, how the response structure changes, how I'd use it in a real backend pipeline, and β just as importantly β when to skip it entirely.
This guide assumes you already have a working Claude API setup. If you need a primer on tool calling or structured JSON output, check out my earlier guides on Claude API tool use and structured outputs first.
What Extended Thinking Actually Does
Standard Claude API calls are direct: prompt in, completion out. Extended thinking adds an intermediate layer. Before generating the visible response, Claude works through the problem internally using the token budget you allocate. Per Anthropic's docs, that thinking content is visible in the API response as a separate content block β you can log it, analyze it, or ignore it β but it does not appear in the final text answer unless you explicitly surface it in your UI.
This matters for two concrete reasons. First, it changes what Claude can reliably do on hard problems. Multi-step logical chains, competing architectural options, long-context analysis β these tend to fall apart when a model tries to produce them in a single forward pass alongside the response text. Giving Claude room to work through the problem first means the final answer is informed by that reasoning, not produced simultaneously with it. Second, you get observability that would otherwise require extra prompting: the thinking traces show you why Claude made a particular recommendation, which is valuable when debugging agentic pipelines where a bad intermediate inference compounds into a worse final output.
One critical point upfront: thinking tokens are billed as output tokens, which cost more than input tokens. Per Anthropic's pricing, if you set budget_tokens: 8000 and Claude uses 6,400 thinking tokens before producing a 500-token response, you're paying for roughly 6,900 output tokens. This is worth factoring in before enabling extended thinking on a high-volume endpoint. The good news is that Claude does not consume budget tokens it doesn't need β unused budget is not charged β so setting a generous ceiling doesn't cost you anything if the problem is simpler than expected.
Your First Extended Thinking Request
The API change is minimal β a single additional thinking parameter on the standard messages endpoint. I'll use the Python SDK throughout since it's the most common choice for backend integrations, but the JSON structure is identical for any HTTP client.
pip install anthropic
Here's the simplest possible extended thinking call:
import anthropic
client = anthropic.Anthropic(api_key="your-api-key")
response = client.messages.create(
model="claude-3-7-sonnet-20250219",
max_tokens=16000, # must cover thinking + output tokens combined
thinking={
"type": "enabled",
"budget_tokens": 8000
},
messages=[{
"role": "user",
"content": (
"I am building a .NET 9 API that needs to process 50,000 webhook events per hour. "
"Events come from three sources with different schemas. I am considering: "
"(a) a single generic handler with a schema registry, "
"(b) three separate typed handler classes, "
"(c) a message-bus approach with consumers per event type. "
"Analyze the trade-offs for maintainability and runtime performance."
)
}]
)
for block in response.content:
if block.type == "thinking":
print("=== THINKING ===")
print(block.thinking)
elif block.type == "text":
print("=== RESPONSE ===")
print(block.text)
Two constraints to know about before you deploy this. First, max_tokens must be large enough to cover both thinking tokens and the final output tokens. Per Anthropic's docs, if budget_tokens is 8,000, your max_tokens must be at least 8,001 plus whatever you expect the final answer to use β otherwise the call fails with a validation error. Second, you cannot set temperature to any value other than 1 when extended thinking is enabled. The API enforces this. If your existing client code sets temperature dynamically, you'll need to conditionally omit it when enabling thinking.
One additional constraint per Anthropic's documentation: extended thinking is not compatible with prompt caching applied to the same message turn that contains the thinking parameter. You can still cache a large system prompt using cache_control on the system message in the same request β and that cache applies normally β but the thinking turn itself is not separately cached. Keep this in mind if you are combining extended thinking with the prompt caching patterns from my prompt caching guide.
Reading the Response: Thinking Blocks Explained
When extended thinking is enabled, response.content becomes an ordered list of content blocks rather than a simple text object. Per Anthropic's docs, the order is always: thinking blocks first, then text blocks. In practice you will get one thinking block followed by one text block for most requests. Here is how to handle this cleanly in a service method:
from anthropic.types import ThinkingBlock, TextBlock
import logging
logger = logging.getLogger(__name__)
def extract_thinking_response(response, request_id: str) -> tuple[str, str]:
"""Returns (thinking_trace, final_answer)."""
thinking_parts = []
text_parts = []
for block in response.content:
if isinstance(block, ThinkingBlock):
thinking_parts.append(block.thinking)
elif isinstance(block, TextBlock):
text_parts.append(block.text)
thinking = "\n\n".join(thinking_parts)
answer = "\n\n".join(text_parts)
# Log thinking for observability β never expose to end users by default
logger.debug("Claude thinking (request_id=%s): %s", request_id, thinking[:800])
return thinking, answer
thinking, answer = extract_thinking_response(response, request_id="req-001")
return {"answer": answer}
The response.usage object breaks out the token counts you need to track costs. response.usage.input_tokens counts the prompt; response.usage.output_tokens is the combined sum of thinking tokens and final-answer tokens. Track this per request type and you'll quickly build intuition for how much of the budget each task category actually consumes. In many cases Claude uses significantly less than the budget you allocated β that's a signal you can lower the budget without any quality regression.
In a production backend, I'd correlate thinking traces with a request ID and store them in a structured log separate from the user-facing response. When a Claude recommendation turns out to be wrong or off-target, the thinking block is usually where the bad assumption lives. It's essentially free diagnostic logging that you would otherwise have to prompt-engineer out of Claude in a separate debug call, and it matters most in agentic workflows where a flawed intermediate inference can compound into a worse final output several steps later.
When Extended Thinking Actually Helps
Not every problem benefits from extended thinking. Per Anthropic's documentation, the intended use cases are problems that require sustained multi-step reasoning: mathematical derivations, complex logical chains, thorough analysis of competing design options, detailed code architecture decisions. The common thread is that the problem has a non-obvious answer that depends on holding multiple constraints in mind simultaneously β and where getting one wrong early leads to a confidently wrong final answer.
For the developer tasks where I'd reach for this β reviewing a .NET project's dependency graph, evaluating architectural options in an API design, reasoning over a long database migration plan β extended thinking noticeably tightens the output. Without it, Claude sometimes elides the middle steps and delivers a confident recommendation that misses a constraint buried in the prompt. With a 5,000β8,000 token budget, it works through those constraints before committing to an answer, and the recommendation is more defensible.
Extended thinking adds both latency and cost with no benefit for straightforward tasks: writing a summary, generating boilerplate, reformatting JSON, writing a docstring, answering a direct factual question. If you are building a high-throughput endpoint where most requests are simple transformations, the right architecture is to leave extended thinking off by default and only enable it for a subset of complex requests you identify through a classifier or routing rule. The next section shows a practical example, and the token budget section covers how to implement cost-aware routing.
A Real Use Case: Architecture Decision Analysis in .NET
Here is a pattern I'd implement in a .NET backend service: a Claude-powered architecture advisor that takes a proposed system design and a list of constraints and returns a structured JSON recommendation. Extended thinking fits well here because the model needs to hold multiple constraints in mind simultaneously β latency, consistency requirements, team skill level, deployment complexity β before committing to a recommendation.
import anthropic
import json
client = anthropic.Anthropic(api_key="your-api-key")
SYSTEM_PROMPT = (
"You are a senior software architect reviewing system design proposals. "
"Analyze the design against the stated constraints and return a JSON recommendation. "
"Be specific about trade-offs. Do not recommend patterns the team has not signaled "
"familiarity with. Return only valid JSON, no markdown fences."
)
def analyze_architecture(design: str, constraints: list[str]) -> dict:
constraints_text = "\n".join(f"- {c}" for c in constraints)
response = client.messages.create(
model="claude-3-7-sonnet-20250219",
max_tokens=12000,
thinking={"type": "enabled", "budget_tokens": 7000},
system=SYSTEM_PROMPT,
messages=[{
"role": "user",
"content": (
f"Design proposal:\n{design}\n\n"
f"Constraints:\n{constraints_text}\n\n"
"Return JSON with keys: recommendation, rationale, "
"trade_offs (list), risks (list), alternative_considered."
)
}]
)
answer = next(b.text for b in response.content if b.type == "text")
return json.loads(answer.strip())
result = analyze_architecture(
design=(
"Event-sourced order management service using PostgreSQL + outbox pattern, "
".NET 9, deployed to Azure Container Apps."
),
constraints=[
"Team of 3 with strong SQL background, limited event sourcing experience",
"P99 write latency target: 200ms",
"10,000 orders per day at launch, 10x growth target in 12 months",
"No dedicated event streaming infrastructure β no Kafka budget"
]
)
print(json.dumps(result, indent=2))
Extended thinking and structured JSON output work together cleanly. You pass JSON instructions in the prompt as normal, and the thinking block reasons through the constraints before committing to the structure. This combination is particularly reliable for complex analysis outputs where you need both rigorous reasoning and a parseable result. For more on the structured outputs side, see my guide on Claude API structured outputs.
If you want to go deeper on the architectural patterns behind production LLM systems β including how to design reliable reasoning pipelines and evaluate output quality β AI Engineering by Chip Huyen (~$50) is one of the more rigorous treatments available. It maps well to the decisions you'll face when integrating extended thinking into a real service.
Token Budget Strategy
Budget sizing is the most important practical decision when adopting extended thinking. Per Anthropic's docs, the minimum is 1,024 tokens, and the maximum varies by model. Unused budget is not charged β Claude stops thinking when it has enough context to produce a good answer. So setting a ceiling higher than needed is safe from a cost perspective, but it does put a floor on how long Claude might take to start streaming the text response on genuinely complex requests.
The calibration approach I'd use: start with a moderate budget (4,000β6,000 tokens), log actual thinking token usage from response.usage over a sample of real requests, and adjust from there. If Claude consistently hits the ceiling β actual usage close to budget_tokens β increase the budget. If usage is consistently below 50% of the allocation, either you're over-allocating or the task category does not benefit enough from extended thinking to justify the cost at all.
For cost-sensitive applications, a two-tier router is the right pattern. Make a fast, cheap classification call β without extended thinking β to determine whether the incoming request is complex enough to warrant it. Route complex requests to an extended-thinking endpoint and simple requests to a standard endpoint. This adds one small API call per request but can more than halve thinking-token spend on mixed-traffic workloads. Pair this with prompt caching on your system prompt via prompt caching β a 2,000-token system prompt cached at cache_control: ephemeral level costs 10% of normal input-token price on repeat calls, per Anthropic's caching docs, which offsets some of the extended thinking overhead.
Streaming Extended Thinking in Production
Extended thinking is fully compatible with streaming. Per Anthropic's documentation, when you stream a response with thinking enabled, you receive content_block_start events for both the thinking block and the text block, with content_block_delta events carrying incremental content for each. This matters for user-facing applications: you can start streaming the final answer to the user as soon as the thinking phase completes, without waiting for the entire response.
thinking_buffer = ""
current_block = None
with client.messages.stream(
model="claude-3-7-sonnet-20250219",
max_tokens=12000,
thinking={"type": "enabled", "budget_tokens": 6000},
messages=[{"role": "user", "content": user_prompt}]
) as stream:
for event in stream:
if not hasattr(event, "type"):
continue
if event.type == "content_block_start":
current_block = event.content_block.type
elif event.type == "content_block_delta":
if current_block == "thinking" and hasattr(event.delta, "thinking"):
thinking_buffer += event.delta.thinking
elif current_block == "text" and hasattr(event.delta, "text"):
yield event.delta.text # stream to user via SSE
logger.info("Thinking trace (truncated): %s", thinking_buffer[:500])
In a FastAPI endpoint using StreamingResponse, you'd yield those text tokens as server-sent events. The thinking phase streams in the background and never reaches the client β you buffer it for logging. The user sees a good time-to-first-token because the text block starts streaming immediately when Claude transitions out of the thinking phase. For high-latency tasks where you allocate 8,000 or more thinking tokens, streaming makes the UX substantially less painful than waiting for the full response before rendering anything.
One thing to watch for in the stream event types: the exact shape of event.delta differs between thinking deltas and text deltas β thinking uses a thinking attribute, text uses a text attribute. The code above handles this correctly with hasattr checks. Always guard against attribute access on the wrong delta type or you will get intermittent AttributeError exceptions in production.
Practical Patterns for Production
A few patterns I'd apply building extended thinking into a real service. First, build graceful fallback. If the extended-thinking call times out or the response fails a downstream validation check, fall back to a standard call without thinking and flag the response for review. Extended thinking is an enhancement, not a hard dependency. Your app should still produce a useful response when it is unavailable.
Second, version your budget configuration. Store budget_tokens in application config rather than hardcoding it. As models improve, the effective budget needed for a given task type may decrease. Being able to adjust the budget without a code deploy is useful, especially in the first weeks after adoption when you are still calibrating usage patterns across different request types.
Third, think carefully about whether to surface thinking traces in your UI. For internal developer tooling or analyst-facing applications where Claude's output informs significant decisions, a collapsible "reasoning" panel that shows the thinking trace builds measurable trust β users can verify the logic rather than just accepting the conclusion. For consumer-facing products, it is usually the wrong call since the raw reasoning is often verbose and technical. Make this decision per product surface, not per API call. A practical reference for these kinds of LLM integration decisions is Hands-On Large Language Models (~$45) β its chapters on building user-facing LLM features are directly applicable to UX decisions around reasoning transparency.
Finally, extended thinking pairs naturally with tool use in agentic workflows. If you are building a pipeline where Claude calls tools, processes results, and produces a final synthesis β a multi-step code analysis agent, a document research pipeline β enabling extended thinking specifically on the synthesis step gives the most value for the cost. Intermediate tool-calling steps usually do not need it; the final synthesis step, where Claude reconciles everything it has gathered, often does. See my guide on Claude API tool use for how to structure that kind of multi-turn agentic loop.
Want Claude dialed in for your workflow?
Book a 1-on-1 Claude setup call: 60 minutes, live, in English or Spanish, recorded for you. $127. Book the call β
Or start with the Claude Prompt Pack: 50 bilingual prompts, $17, instant download.