DOC: ChatOpenAI endpoint resolution — OPENAI_API_BASE takes precedence over OPENAI_BASE_URL, documented in Python but not in JS
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:
baseURL: fields?.configuration?.baseURL
?? serializedBaseUrl
?? (getEnvironmentVariable("OPENAI_API_BASE") || getEnvironmentVariable("OPENAI_BASE_URL") || void 0)So the order is:
configuration.baseURL- the serialized
baseUrlfield OPENAI_API_BASEOPENAI_BASE_URL- the SDK default
Measured to confirm, against a local endpoint:
### 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 winsWhy 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):
- Explicit
base_url(oropenai_api_base) kwarg.- Env var
OPENAI_API_BASE(read by LangChain at init).- Env var
OPENAI_BASE_URL(read by the underlyingopenaiSDK 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.:
/**
* 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