The Residency Tax

Keeping LLM inference in region now costs about 10% more on every token line at Anthropic, OpenAI, Google Vertex and most Azure Data Zone deployments. On Bedrock the gap runs from 0% in Stockholm to 33% in Frankfurt for the same open-weight model. Most teams pin the whole workspace and pay the premium on every request. If 30% of a $100,000 monthly bill is regulated, pinning per request cuts the premium from $10,000 to $3,000 a month. The bigger lever is the model: a pinned Haiku 5.5 request costs 1/40 of a pinned Opus 5.5 request. Includes residency.py, 56 lines that pin per request, fail closed, verify where each answer was served, and price blanket against per-request pinning on your usage log.

Published 2026-10-27 by Dor Amir on the Nadir blog.

Filed under FinOps & Governance.

TL;DR.

Keeping LLM inference in one region now has a price on most rate cards. Anthropic, OpenAI and Google Vertex all charge about 10% more for it, on every token line. Most teams turn it on the way compliance asks for it: once, for the whole workspace. That pays the premium on every request, including the ones that never touch regulated data.

Premiums are from Anthropic's data residency docs and two third-party pricing references compiled from provider pages in August and September 2026. The $100,000 bill and the request shapes are ours, and are illustrations, not measurements. No figure here comes from Nadir customer data. This is a cost post, not legal advice.

What in-region costs.

Data residency used to be a sales conversation: an enterprise contract, a dedicated deployment, a number nobody published. In 2026 it became a line on the rate card. Here's what the major options add over the same model on a global endpoint.

Horizontal bar chart of the price premium for running the same model in region. Bedrock Claude 3.5 Sonnet in EU regions 0%. Bedrock gpt-oss-120b in Stockholm 0%. Anthropic API with inference_geo us +10%. OpenAI regional endpoint +10%. Vertex Gemini non-global endpoint +10%. Bedrock Mistral Large 3 in Ireland +18%. Azure EU Data Zone GPT-6 +20%. Bedrock gpt-oss-120b in Frankfurt +33%. Bedrock Gemma 3 27B in London +57%.
Horizontal bar chart of the price premium for running the same model in region. Bedrock Claude 3.5 Sonnet in EU regions 0%. Bedrock gpt-oss-120b in Stockholm 0%. Anthropic API with inference_geo us +10%. OpenAI regional endpoint +10%. Vertex Gemini non-global endpoint +10%. Bedrock Mistral Large 3 in Ireland +18%. Azure EU Data Zone GPT-6 +20%. Bedrock gpt-oss-120b in Frankfurt +33%. Bedrock Gemma 3 27B in London +57%.
OptionPremiumApplies toCalled residency?
Anthropic API, inference_geo: "us"+10%Claude 4.6 and later, every token lineYes
OpenAI regional processing endpoint+10%Models released on or after March 5, 2026Yes
Google Vertex, non-global endpoint+10%Gemini 3 and later, since July 1, 2026Yes
Azure OpenAI, Data Zone+10% (GPT-6: +20%)Most models, cache lines includedYes
Mistral, regional endpoint1.1x listStandard API is EU-hosted by defaultYes
Bedrock, Claude in EU regions+10% (Haiku 4.5, Sonnet 5, Opus 5.5)Varies by model and regionMostly no
Bedrock, open-weight models0% to +57%Varies by model and regionNo

Four details matter more than the headline number.

It applies to cache reads too. Anthropic's 1.1x covers input, output, cache writes and cache reads. On a coding agent, where most tokens are cache reads, the premium is still a flat 10% of the bill. Caching doesn't dilute it.

Claude has no EU geo on the first-party API. inference_geo takes "global" or "us", and "us" is the only workspace geo. EU-regional Claude means Bedrock or Vertex regional endpoints, priced by those platforms.

Azure is moving. Microsoft's pricing page carries a notice that pricing for EU Data Zone and non-US regional deployments increases from September 1, 2026, without saying by how much. Check the current rows before you budget.

Region choice inside Europe is a cost decision. On Bedrock, gpt-oss-120b costs the US East price in Stockholm and 33% more in Frankfurt or Milan. If your requirement is "in the EU," not "in Germany," that's a third of the bill. AWS doesn't label these gaps residency, and they aren't, but residency is often the reason a team is in that region.

Why most teams pay it on everything.

The way residency gets turned on explains the bill. A customer contract or a security review says "inference must stay in region." Someone sets the workspace default, or creates a regional project, and points every service at it. Done, compliant, and 10% more on every request.

Anthropic's own migration shows how this happens by default. Organizations that had opted out of global routing under the old setting were moved to allowed_inference_geos: ["us"] and default_inference_geo: "us", with "no code changes needed." That keeps them compliant. It also means that every request to a Claude 4.6 or later model from those workspaces bills at 1.1x, whether it's a regulated patient summary or a unit test docstring.

The same blanket shows up in two more places:

Usually, not all of your traffic is covered by the requirement. Residency obligations tend to attach to specific data (health records, payment data, a government customer's documents) or specific tenants (the EU customer whose contract says so). GDPR regulates transfers out of the EU rather than banning them, so whether a given request must stay in region is a question for your contracts and your counsel, not a property of the whole workload. The internal tooling, the anonymized analytics, the coding agent working on your own repo, and the customers with no residency clause often don't need it.

Pin the 30%, not the 100%.

Take a $100,000 monthly bill at global prices, and say 30% of the spend is regulated: it comes from tenants or data classes that must stay in region.

Grouped bar chart of the monthly residency premium on a $100,000 bill at 1.1x. Blanket pin costs $10,000 at every regulated share. Per-request pin costs $1,000 at 10% regulated, $3,000 at 30%, $5,000 at 50%, $8,000 at 80%.
Grouped bar chart of the monthly residency premium on a $100,000 bill at 1.1x. Blanket pin costs $10,000 at every regulated share. Per-request pin costs $1,000 at 10% regulated, $3,000 at 30%, $5,000 at 50%, $8,000 at 80%.
Regulated share of spendBlanket pinPer-request pinSaved per monthSaved per year
10%$10,000$1,000$9,000$108,000
30%$10,000$3,000$7,000$84,000
50%$10,000$5,000$5,000$60,000
80%$10,000$8,000$2,000$24,000

The arithmetic is simple: per-request pinning pays the premium only on pinned spend. On Azure's GPT-6 Data Zone at +20%, every number in the table doubles.

Two things make it less simple in practice.

The classification has to be right, and wrong in the safe direction. A missed regulated request served globally is a compliance incident. An unregulated request served in region is a 10% overpayment. Those aren't symmetric, so the policy should fail closed: unknown tenant, unknown data class or a failed lookup means pinned. Saving 10% isn't worth a breach of contract.

Pinning splits sessions. Requests from one conversation should stay in one geo. We haven't seen any provider document that prompt caches are shared across geos, so assume a request that switches geo mid-session starts its cache over and pays a fresh cache write, the same penalty we measured for routers that switch models mid-session in Your Router Is Fighting Your Prompt Cache. Decide the geo per tenant and session, not per turn.

If 80% of your spend is regulated, per-request pinning saves 2% of the bill and adds a policy to maintain. Keep the blanket. This is worth doing when the regulated share is well under half.

The premium is 10%. The tier is 40x.

The bigger lever on a regulated workload isn't the pin. It's the model.

Horizontal bar chart of cost per 1,000 chat requests with 4,000 input and 400 output tokens. Claude Opus 5.5 global $24.00. Opus 5.5 pinned $26.40. Sonnet 5.5 pinned $13.20. Haiku 5.5 pinned $0.66.
Horizontal bar chart of cost per 1,000 chat requests with 4,000 input and 400 output tokens. Claude Opus 5.5 global $24.00. Opus 5.5 pinned $26.40. Sonnet 5.5 pinned $13.20. Haiku 5.5 pinned $0.66.

On a 4,000-token-in, 400-token-out chat request, pinning Opus 5.5 to the US adds $2.40 per 1,000 requests. Serving the same request pinned on Haiku 5.5 costs $0.66 per 1,000, $23.34 less than unpinned Opus, if Haiku can do the job.

Regulated traffic is often where teams are most conservative about models: it's the health record, the contract, the payment dispute, so it goes to the biggest model by default. Some of it needs that. A lot of it is extraction, classification and templated summaries that a small model finishes. Teams that argue for a week over a 10% residency premium often leave a 10x to 40x tier gap on the same requests.

Both decisions belong at the request level, and they compose: first where (geo, from policy), then which model (the cheapest one available in that geo that clears your quality bar). Getting the order right matters. The geo constrains the model set, never the other way round.

Tutorial: residency.py.

residency.py does three things. pick_geo() decides the geo for one request from the tenant and the text. send() makes the Claude call with that geo and refuses an answer served elsewhere, using the inference_geo field Anthropic returns in usage. premium() reads a usage log and prices blanket against per-request pinning.

"""residency.py: pin only the requests that must stay in region.

pick_geo() decides per request. send() calls Claude with that geo and checks
where inference ran. premium() reads a usage log and compares a blanket pin
against a per-request pin.
"""
import csv
import re
import sys

UPLIFT = 0.10  # +10%: Anthropic inference_geo "us", OpenAI regional, Vertex non-global
PINNED_TENANTS = {"us-gov", "us-health"}  # contracts that require US-only inference
SCAN = re.compile(
    r"\b\d{3}-\d{2}-\d{4}\b"                 # US SSN
    r"|\b(?:MRN|patient id)[:# ]*\d{5,}\b"   # medical record numbers
    r"|\b(?:\d[ -]?){13,16}\b",              # card numbers
    re.I,
)


def pick_geo(tenant, text, known_tenants):
    """'us' or 'global'. Unknown tenants fail closed, the scanner only adds pins."""
    if tenant not in known_tenants or tenant in PINNED_TENANTS:
        return "us"
    return "us" if SCAN.search(text) else "global"


def send(client, model, messages, geo):
    """One Messages call pinned to geo; refuses an answer served elsewhere."""
    r = client.messages.create(model=model, max_tokens=1024,
                               inference_geo=geo, messages=messages)
    if geo == "us" and r.usage.inference_geo != "us":
        raise RuntimeError(f"asked for us, served in {r.usage.inference_geo}")
    return r


def premium(path):
    """Blanket vs per-request pinning for a log of tenant, text, cost_usd rows."""
    rows = list(csv.DictReader(open(path, newline="")))
    known = {r["tenant"] for r in rows if r["tenant"] != "unknown"}
    base = sum(float(r["cost_usd"]) for r in rows)
    pinned = [r for r in rows if pick_geo(r["tenant"], r["text"], known) == "us"]
    pinned_cost = sum(float(r["cost_usd"]) for r in pinned)
    by_tenant = sum(float(r["cost_usd"]) for r in pinned if r["tenant"] in PINNED_TENANTS)
    print(f"{len(rows):,} requests, ${base:,.2f} at global prices")
    print(f"  pinned by contract:   {by_tenant / base:6.1%} of spend")
    print(f"  pinned by scanner or unknown tenant: {(pinned_cost - by_tenant) / base:6.1%}")
    print(f"  blanket pin:          ${base * (1 + UPLIFT):,.2f}  (+${base * UPLIFT:,.2f})")
    print(f"  per-request pin:      ${base + pinned_cost * UPLIFT:,.2f}  "
          f"(+${pinned_cost * UPLIFT:,.2f})")
    print(f"  saved vs blanket:     ${(base - pinned_cost) * UPLIFT:,.2f} "
          f"({(base - pinned_cost) / base:.1%} of spend runs global)")


if __name__ == "__main__":
    premium(sys.argv[1])

On a synthetic 20,000-request log with eight tenants, two of them under a US-only contract, it prints:

20,000 requests, $1,214.28 at global prices
  pinned by contract:    20.2% of spend
  pinned by scanner or unknown tenant:  11.3%
  blanket pin:          $1,335.71  (+$121.43)
  per-request pin:      $1,252.52  (+$38.24)
  saved vs blanket:     $83.19 (68.5% of spend runs global)

How to adapt it:

  1. Put the contract list first. PINNED_TENANTS should come from the same place your contracts are tracked, not from a regex. Tenant metadata is deterministic. The scanner is a backstop.
  2. Let the scanner only add pins. The card-number pattern above will match some order numbers and phone numbers. That's fine: a false match costs 10% on one request. Never let a scanner remove a pin that tenant policy set.
  3. Keep the check in `send()`. Anthropic returns where inference actually ran in usage.inference_geo. Log it on every request, and alert on any pinned request that comes back different. That log is also the evidence your compliance team will ask for.
  4. Set `allowed_inference_geos` anyway. For a workspace that should only ever serve regulated tenants, restrict it to ["us"] in the Console so a missing parameter can't leak a request. Run per-request pinning from a separate workspace that allows both.
  5. Map other providers the same way. OpenAI's residency is per project with its own regional endpoint, and Bedrock and Vertex pick the region by endpoint or inference profile. The policy is the same, pick_geo() returns a region, and the client for that region does the rest.

Where Nadir fits.

residency.py decides where. Nadir decides which model, per request, within the set you allow.

Run the router in your region. The hosted Nadir service stores data in the United States, and we don't currently offer other regions on it. For residency workloads, Nadir runs as one container inside your own VPC, in whatever region you choose, with no calls home. Point it at models in your own Bedrock account and the calls stay inside your AWS boundary, or register self-hosted open weights served with vLLM, TGI or Ollama as tiers. With store_prompts=false, logs keep a SHA-256 hash instead of the prompt text.

Route within the allowed set. Give the in-region deployment a ladder of in-region models only, and model="auto" sends each request to the cheapest of them that clears your quality floor. That's the 40x lever from the chart above, applied after the geo decision rather than instead of it. The model that served each request and its cost come back on the response, so the per-tenant split in the tutorial exists for every request without a separate export.

If you'd rather measure before anything changes, Observe mode serves exactly the model you asked for and records what routing would have chosen. With your own provider keys, Nadir charges no fee on any plan, and the provider bills you directly. Savings depend on your workload, and nothing in this post forecasts yours.

Start with a free key, or run residency.py on a week of your usage log first and see how much of your premium is buying compliance.

Conclusion.

Data residency now has a list price: about 10% on Claude, OpenAI, Gemini and most of Azure, on every token line, and anywhere from 0% to 57% on Bedrock depending on which region you pick. Most teams pay it on all their traffic because they enabled it for the whole workspace. Pin per request when the regulated share is well under half, fail closed when you're unsure, verify where each answer was served, and choose the region inside your requirement by price. Then spend the effort where the bigger number is: the model tier serving those requests.


Anthropic figures are from its data residency documentation, including the 1.1x multiplier on all token categories, the legacy opt-out migration, Priority Tier burndown and shared rate limits. OpenAI, Vertex, Azure, Mistral and Bedrock premiums are from two third-party references compiled from provider pricing pages: Digital Applied (rates retrieved August 25, 2026) and Aliteq (verified September 27, 2026). They disagree in places, and regional prices change often, so check the provider pages before you rely on any figure here. The $100,000 bill, the chat request shape and the synthetic usage log are ours, and are illustrations, not measurements. Claude prices are October 27, 2026 list prices, with Haiku 5.5 at its rate for prompts up to 100K tokens. Nothing here is legal advice. Sources: [Anthropic, Data residency](https://platform.claude.com/docs/en/manage-claude/data-residency). [Anthropic, Pricing](https://www.anthropic.com/pricing). [Digital Applied, "What Data Residency Actually Costs: A Pricing Reference," August 25, 2026](https://www.digitalapplied.com/blog/ai-data-residency-cost-premiums-reference). [Aliteq, "EU Data Residency for AI APIs: What OpenAI, Azure, Bedrock, Vertex, Mistral and Claude Charge in 2026," September 27, 2026](https://aliteq.com/eu-data-residency-ai-api-cost-2026). [OpenAI, API pricing](https://openai.com/api/pricing/). [Microsoft, Azure OpenAI pricing](https://azure.microsoft.com/en-us/pricing/details/cognitive-services/openai-service/). [Google Cloud, Vertex AI pricing](https://cloud.google.com/vertex-ai/generative-ai/pricing). [AWS, Amazon Bedrock pricing](https://aws.amazon.com/bedrock/pricing/).

More on finops & governance

What Nadir is

Nadir is an LLM router. Nadir sends each prompt to the cheapest model that can handle it. A small decision model reads each prompt against your model menu and picks the lowest-cost model it expects to handle it. When the decision model is uncertain or unavailable, the request goes to the strongest model on the menu. The routing step makes no call to your model provider.

Nadir runs two ways. The decision API returns a model, reasoning-effort, cache, context, and policy recommendation without calling a model provider, beside the gateway you already run. That is how a shadow-mode evaluation works, and its projected savings stay advisory. The OpenAI compatible managed proxy executes the route, and migration is a two-line change: point the base URL at api.getnadir.com and set model to auto. On that path an optional verifier can score a complete non-streaming answer and escalate to a stronger model when it misses the configured bar. Streaming bypasses post-generation verification. BYOK is supported on every tier.

For coding agents, Nadir Auto is a terminal launcher for Claude Code or Codex that asks Nadir for the main-session model before each turn, with your configured model as the fallback and cost ceiling. Delegation integrations for Claude Code, Codex, or Cursor instead recommend a model tier for subagent work, and the agent decides; the Claude plugin can also move a main-thread turn to Haiku when Nadir's cache check prices it cheaper, unless its switch_main_model option is off. Either way inference runs on your own provider account, so Nadir holds no provider keys on that path.

What the numbers are, and what they are not

Nadir publishes each evaluation with its scope. On checkable code, run-check-escalate solved 392 of 395 common HumanEval and MBPP problems (99.2%), graded by running the canonical tests; that applies only to tasks with runnable deterministic tests. Nadir-Tumbler posts an arena_score of 72.3 on RouterArena's public scorer, 5th of 23 routers, which measures the routing decision on RouterArena's own model pool. A reference-assisted RouterBench evaluation over 11,420 held-out triples produced a 60% lower projected cost than always-Opus with about 98% retained quality and a 1.7% catastrophic-route rate. That experiment gave the verifier the expensive-model reference answer, which production does not have, so it is a research ceiling and not the deployed path.

None of these is a production guarantee, a universal savings rate, or a forecast for any particular workload. Customer savings are reported from measured execution against a declared baseline, and customer quality only from outcome-labelled traffic. Projected savings and realized savings are separate artifacts and are never blended.

Design-partner program

Three rungs, picked by risk appetite. Rung 0 Shadow runs advisory decision calls alongside live traffic and returns a projected receipt, with nothing in the request path changed. Rung 1 Hosted is the two-line swap on a production slice and returns a realized receipt. Rung 2 On-prem is a supervised six-week proof of concept inside the partner's VPC, where no prompt, response, or usage reaches Nadir. The commitments are the same at every rung. Apply for a rung directly: Rung 0 Shadow, Rung 1 Hosted, or Rung 2 On-prem. Not sure which fits? Start at getnadir.com/contact/?reason=design-partner.

Licensing

NadirClaw is the self-hosted core, source-available under the PolyForm Noncommercial License. Source-available is the correct label; NadirClaw is not open source. Nadir Route's hosted plan has no base fee and charges a variable fee only on measured savings from requests Nadir executed.

Pages on this site

Machine-readable summaries of this site: llms.txt and llms-full.txt.