#11635·langchainjs

DOC: ChatOpenAI endpoint resolution — OPENAI_API_BASE takes precedence over OPENAI_BASE_URL, documented in Python but not in JS

Author: xizhuomengcontinCreated Sep 14, 2026Updated Sep 14, 2026

Issue

ChatOpenAI resolves its endpoint from two environment variables with a defined precedence, and neither is documented in the JS package. The Python package documents exactly this, so it is a docs-parity gap rather than a design question.

The behaviour

@langchain/openai, dist/chat_models/base.js:229:

javascript
baseURL: fields?.configuration?.baseURL
      ?? serializedBaseUrl
      ?? (getEnvironmentVariable("OPENAI_API_BASE") || getEnvironmentVariable("OPENAI_BASE_URL") || void 0)

So the order is:

  1. configuration.baseURL
  2. the serialized baseUrl field
  3. OPENAI_API_BASE
  4. OPENAI_BASE_URL
  5. the SDK default

Measured to confirm, against a local endpoint:

bash
### only OPENAI_BASE_URL set
resolved baseURL = http://127.0.0.1:52991/v1

### only OPENAI_API_BASE set
resolved baseURL = http://127.0.0.1:52992/v1

### both set (BASE_URL→52991, API_BASE→52992)
resolved baseURL = http://127.0.0.1:52992/v1     ← API_BASE wins

Why it is worth documenting

The bare openai SDK reads only OPENAI_BASE_URL (openai/index.js:72: baseURL = Core.readEnv('OPENAI_BASE_URL')) and ignores OPENAI_API_BASE entirely. LangChain adds OPENAI_API_BASE and gives it priority. That inversion means a leftover OPENAI_API_BASE — from an older tutorial, a parent-directory .env, a container image — silently wins over an OPENAI_BASE_URL the user just set, and requests go to the other endpoint carrying the configured API key. Nothing errors; the symptom is "my proxy/gateway setting has no effect".

Anyone arriving from the raw SDK's mental model will set OPENAI_BASE_URL and be confused, and nothing in the JS typings or docs tells them otherwise.

Parity with Python

langchain-openai (Python) spells the order out in the ChatOpenAI docstring — chat_models/base.py, around lines 797-801:

Resolution order (first match wins):

  1. Explicit base_url (or openai_api_base) kwarg.
  2. Env var OPENAI_API_BASE (read by LangChain at init).
  3. Env var OPENAI_BASE_URL (read by the underlying openai SDK client).

The JS implementation follows the same order (plus the extra baseUrl rung) but documents neither variable — dist/chat_models/base.d.ts does not mention either.

Suggested fix

Mirror the Python docstring on the JS ChatOpenAIFields / configuration typing, e.g.:

typescript
/**
 * Base URL for API requests. Resolution order (first match wins):
 * 1. `configuration.baseURL`
 * 2. `baseUrl`
 * 3. env `OPENAI_API_BASE`   (read by LangChain — takes precedence)
 * 4. env `OPENAI_BASE_URL`   (read by the underlying `openai` SDK)
 */

Happy to open the PR if that wording works for you; I did not send one unprompted since the exact phrasing is a maintainer call.

Related, and deliberately not filed as a bug

Flowise's ChatOpenAI node builds configuration = { baseURL: basePath, defaultHeaders } whenever either input is set, so supplying only custom headers passes baseURL: undefined explicitly. I checked whether that clobbers the env fallback — it does not, undefined falls through to step 3/4 correctly. Mentioning it only because it is the kind of thing someone might "fix" on suspicion.

System Info

@langchain/openai as resolved on 2026-09-14, openai JS SDK 6.x, Node 22.23.2, Windows. Behaviour measured against a deterministic local endpoint rather than a live provider.

Source: langchain-ai/langchainjs