How to Implement Custom API Keys and Base URLs for AI Models in Next AI Draw.io
Next AI Draw.io supports custom environment variable names for API keys and base URLs through the apiKeyEnv and baseUrlEnv fields in ServerProviderSchema, enabling multi-tenant deployments and self-hosted endpoints without modifying core SDK code.
The open-source repository DayuanJiang/next-ai-draw-io provides a flexible architecture for managing multiple AI providers. You can implement custom API keys and base URLs for AI models in Next AI Draw.io by configuring the ai-models.json file and leveraging the resolution logic in lib/ai-providers.ts. This approach allows teams to rotate credentials, support multiple teams with separate keys, or route traffic to private endpoints.
Configure Custom Environment Variables in ai-models.json
The server-side model configuration uses ServerProviderSchema defined in lib/server-model-config.ts to validate custom environment variable mappings. Each provider entry can specify apiKeyEnv (string or array of strings) and baseUrlEnv (string) to override default SDK behavior.
Create or edit ai-models.json at the project root:
{
"providers": [
{
"name": "OpenAI Production",
"provider": "openai",
"models": ["gpt-4o", "gpt-4o-mini"],
"apiKeyEnv": ["OPENAI_API_KEY_TEAM_A", "OPENAI_API_KEY_TEAM_B"],
"baseUrlEnv": "OPENAI_CUSTOM_BASE_URL",
"default": true
}
]
}
Alternatively, set the AI_MODELS_CONFIG environment variable to a JSON string with the same shape. The loadFlattenedServerModels() function in lib/server-model-config.ts reads this configuration and flattens each model entry while preserving the custom environment variable names:
flattened.push({
id,
modelId,
provider: p.provider,
providerLabel,
isDefault,
apiKeyEnv: p.apiKeyEnv,
baseUrlEnv: p.baseUrlEnv,
})
Add the corresponding secrets to your .env.local:
OPENAI_API_KEY_TEAM_A=sk-****************************
OPENAI_API_KEY_TEAM_B=sk-****************************
OPENAI_CUSTOM_BASE_URL=https://my.private-openai.example.com/v1
When apiKeyEnv is an array, the system randomly selects a defined key for load balancing.
Resolution Logic for API Keys and Base URLs
The core credential resolution happens in lib/ai-providers.ts through three key functions that determine which values take precedence.
The resolveApiKey Function
The resolveApiKey function implements a fallback chain:
- User-provided
overrides.apiKey(highest priority) - Custom environment variable(s) from
overrides.apiKeyEnv - Default environment variable (e.g.,
OPENAI_API_KEY)
When multiple keys are configured, the function randomly selects one to distribute load:
function resolveApiKey(overrides, defaultEnvVar) {
if (overrides?.apiKey) return overrides.apiKey;
if (overrides?.apiKeyEnv) {
if (Array.isArray(overrides.apiKeyEnv)) {
const valid = overrides.apiKeyEnv.filter(v => process.env[v]);
if (valid.length) return process.env[valid[Math.random() * valid.length | 0]];
} else {
return process.env[overrides.apiKeyEnv];
}
}
return process.env[defaultEnvVar];
}
The resolveBaseURL Function
The resolveBaseURL function determines the endpoint based on credential ownership. If a user supplies their own API key, only their baseUrl or the provider default is used. Otherwise, the server-side serverBaseUrl from baseUrlEnv is applied.
The resolveBaseUrlEnv wrapper reads the value of a custom base URL environment variable, falling back to the default if not specified.
Enabling User Overrides in the UI
The frontend can expose custom credentials through the ClientOverrides interface defined in lib/ai-providers.ts:
export interface ClientOverrides {
provider?: string | null;
baseUrl?: string | null;
apiKey?: string | null;
modelId?: string | null;
apiKeyEnv?: string | string[];
baseUrlEnv?: string;
}
The components/provider-credentials-fields.tsx component renders input fields that map user entries to these override properties:
<TextInput
label="API Key"
placeholder={model.apiKeyEnv?.join(', ') || 'API key'}
value={overrides.apiKey ?? ''}
onChange={e => setOverrides({ ...overrides, apiKey: e.target.value })}
/>
<TextInput
label="Base URL"
placeholder={model.baseUrlEnv || 'https://…'}
value={overrides.baseUrl ?? ''}
onChange={e => setOverrides({ ...overrides, baseUrl: e.target.value })}
/>
When the user selects a model, the application calls validateProviderCredentials(provider, overrides?.apiKeyEnv) to ensure at least one of the supplied environment variables is present before instantiation.
Practical Implementation Example
To use a custom provider configuration in your application code, call getAIModel with overrides referencing your custom environment variables:
// src/lib/custom-openai-example.ts
import { getAIModel } from '@/lib/ai-providers';
export async function generateDiagram(prompt: string) {
const overrides = {
modelId: 'gpt-4o',
apiKeyEnv: ['OPENAI_API_KEY_TEAM_A', 'OPENAI_API_KEY_TEAM_B'],
baseUrlEnv: 'OPENAI_CUSTOM_BASE_URL',
};
const { model } = getAIModel(overrides);
const response = await model.generate({
messages: [{ role: 'user', content: prompt }],
});
return response;
}
This configuration instructs the factory to:
- Randomly select either
OPENAI_API_KEY_TEAM_AorOPENAI_API_KEY_TEAM_B - Route requests to
https://my.private-openai.example.com/v1 - Return a ready-to-use AI SDK model instance
Summary
- Declare custom environment variables using
apiKeyEnvandbaseUrlEnvinai-models.jsonor theAI_MODELS_CONFIGenvironment variable - Load-balance multiple keys by providing an array of environment variable names, which
resolveApiKeyselects from randomly - Validate credentials automatically through
validateProviderCredentialsbefore model instantiation - Override at runtime via
ClientOverridesincomponents/provider-credentials-fields.tsxfor user-specific credentials - Route to private endpoints by specifying custom
baseUrlEnvvalues that resolve throughresolveBaseURL
Frequently Asked Questions
Can I specify multiple API keys for load balancing?
Yes. Set apiKeyEnv to an array of environment variable names in your provider configuration. The resolveApiKey function in lib/ai-providers.ts filters for defined variables and randomly selects one, distributing requests across multiple keys automatically.
What happens if both custom and default environment variables are set?
The resolution logic follows strict precedence: user-provided apiKey overrides everything, then custom apiKeyEnv values are checked, and finally the default SDK environment variable (like OPENAI_API_KEY) is used as fallback. This ensures explicit overrides always take priority.
How do I configure a self-hosted OpenAI-compatible endpoint?
Define a baseUrlEnv field in your ai-models.json provider entry pointing to your custom environment variable. Set that variable to your self-hosted URL (e.g., https://localhost:3000/v1). The resolveBaseURL function will route requests there while still using the OpenAI SDK provider implementation.
Is it possible to override the base URL on the client side?
Yes. Users can input custom base URLs through the components/provider-credentials-fields.tsx interface, which populates ClientOverrides.baseUrl. When a user provides their own API key, the resolveBaseURL logic respects their custom base URL over the server-side baseUrlEnv configuration.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →