DEV Community

Harvey He
Harvey He

Posted on

Claude Code on a non-Anthropic backend — the env vars that actually matter

I run an OpenAI-compatible gateway, so I spend a lot of time watching people try to point Claude Code at something that isn't api.anthropic.com. Most of them get it working in about two minutes. Most of them also miss the three variables that actually change their bill and their error rate.

Here's the short version. Everything below is from Anthropic's own env var reference, plus things I hit myself.

The minimum that works

export ANTHROPIC_BASE_URL=https://your-endpoint/v1
export ANTHROPIC_AUTH_TOKEN=sk-your-key
export ANTHROPIC_MODEL=some-model-id
Enter fullscreen mode Exit fullscreen mode

That's it. Three lines and Claude Code talks to your backend instead.

The auth header trap

This one cost me an hour.

  • ANTHROPIC_API_KEY sends your value as X-Api-Key
  • ANTHROPIC_AUTH_TOKEN sends it as Authorization: Bearer <value>

Anthropic's own API wants X-Api-Key. Nearly every OpenAI-compatible backend — LiteLLM, One API, New-API, most resellers — wants Authorization: Bearer. If you set the wrong one you get a 401 that looks like a bad key, and you'll spend that hour rotating keys instead of reading the header.

If your backend speaks Bearer, use ANTHROPIC_AUTH_TOKEN. Save yourself the hour.

The alias variables matter more than ANTHROPIC_MODEL

set ANTHROPIC_MODEL changes the main model. That's the obvious one. The ones that actually move your cost are:

export ANTHROPIC_DEFAULT_HAIKU_MODEL=cheap-model-id
export ANTHROPIC_DEFAULT_SONNET_MODEL=mid-model-id
export ANTHROPIC_DEFAULT_OPUS_MODEL=strong-model-id
Enter fullscreen mode Exit fullscreen mode

Why the Haiku one matters most: Claude Code doesn't only use Haiku when you ask for it. It uses that alias for background work — summarising long files, condensing context, the little housekeeping calls that happen constantly during a session. Those calls are high volume and they don't need a strong model.

Point ANTHROPIC_DEFAULT_HAIKU_MODEL at your cheapest model and your per-session cost drops more than it would from downgrading the main model. That's the opposite of what most people try first.

One dead variable worth knowing about: ANTHROPIC_SMALL_FAST_MODEL is deprecated. It was the old way to set the background model. If you set it today, it silently does nothing. You'll think you've configured something and you haven't. Use ANTHROPIC_DEFAULT_HAIKU_MODEL.

ANTHROPIC_DEFAULT_OPUS_MODEL also does something non-obvious — it's what the opusplan setting uses while Plan Mode is active. If you skip it and only set Sonnet, plan mode behaves differently than you'd expect.

The one that surprised me

When ANTHROPIC_BASE_URL points at a non-first-party host, MCP tool search is disabled by default. Explains itself as "MCP tools aren't working" rather than "a feature was turned off because your endpoint isn't Anthropic's".

export ENABLE_TOOL_SEARCH=true
Enter fullscreen mode Exit fullscreen mode

Set that if your proxy forwards tool_reference blocks. From v2.1.196, Remote Control is also disabled when the base URL isn't api.anthropic.com — same behaviour as Bedrock and Vertex. That's intentional, not a bug on your end.

If your backend is slow, set these before you debug anything else

export API_TIMEOUT_MS=600000              # default is 600000 (10 min)
export API_FORCE_IDLE_TIMEOUT=0           # kills the 5-min idle abort
Enter fullscreen mode Exit fullscreen mode

API_FORCE_IDLE_TIMEOUT is the one people miss. There's a 5-minute body idle timeout that aborts a streaming response when no bytes arrive. A slow gateway that pauses between chunks trips it, and you'll see Claude Code just... stop, mid-sentence, with no useful error. 0 turns that timeout off.

Worth saying out loud: I learned this one the hard way. I ran three requests through my own gateway on Aug 31 and one of them took 92 seconds and then timed out. Two finished in 2.4s and 11.2s. Same endpoint, same model, same payload. The variance was upstream, not mine — but nothing on my side cut the request loose, so the client just sat there. A gateway without a request timeout isn't a safety net, it's a place to wait.

Today the same test three times came back in 1.64s, 2.53s and 8.40s. Still a 5x spread. That's the honest picture — I'm not going to pretend it's flat.

How to check it before you blame Claude Code

Don't debug through the CLI. Hit the endpoint directly:

curl -s https://your-endpoint/v1/chat/completions \
  -H "Authorization: Bearer $ANTHROPIC_AUTH_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"model":"your-model","messages":[{"role":"user","content":"say OK"}],"max_tokens":10}'
Enter fullscreen mode Exit fullscreen mode

If that fails, it's your endpoint, your key, or your header — not Claude Code. If that works and Claude Code doesn't, it's the variables above. Run it a few times too. One success tells you almost nothing.

Two things that will bite you

Caching. If your backend caches prompt prefixes, the system prompt Claude Code sends is mostly stable, so you should get a high hit rate. But hit rates are per-provider and they change. Mine changed by 15x on Sept 1 when my upstream re-priced cached input. Don't build a budget on a rate you measured once.

Tool calling. Not every model on every backend does function calling reliably. If tool calls fail on your gateway but work on Anthropic's API, that's a model capability gap, not a config problem. Test it before you move a whole workflow over.

That's the list

ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN to connect. ANTHROPIC_DEFAULT_HAIKU_MODEL to cut cost. ENABLE_TOOL_SEARCH if MCP breaks. API_FORCE_IDLE_TIMEOUT if streams die. Four things, and one deprecated variable to stop using.


I'm Harvey. I run an OpenAI-compatible gateway at keheai.com and I write about the parts that break. If you've hit something I haven't listed here, I'd genuinely like to know what it was.

Top comments (0)