How to Configure Multiple AI Providers for Server-Side Models in Next AI Draw.io
Next AI Draw.io supports multiple AI providers through a layered configuration system that merges environment variables, JSON configuration files, and admin UI settings, defined primarily in lib/server-model-config.ts.
The DayuanJiang/next-ai-draw-io repository enables self-hosted AI diagram generation by supporting simultaneous connections to multiple LLM providers. Configuring multiple AI providers for server-side models allows you to load-balance across different API keys, route specific models to distinct endpoints, and maintain fallback options for high-availability deployments.
Configuration Hierarchy and Priority
The configuration loader implements a three-tier priority system defined in lib/server-model-config.ts. The system merges these sources with any providers added through the admin interface, which are stored in settings.json under the ADMIN_PROVIDERS key.
High-Priority Environment Variables
The AI_MODELS_CONFIG environment variable accepts a JSON string containing the full provider array. This takes precedence over all other configuration methods.
Static Configuration Files
If the environment variable is unset, the system looks for ai-models.json at the repository root, or at a custom path specified by AI_MODELS_CONFIG_PATH.
Legacy Fallback Options
As a final fallback, the system parses comma-separated values from AI_MODEL and AI_PROVIDER to create a single provider entry.
Provider Schema and Model Flattening
Each provider must conform to the ServerProviderSchema defined in lib/server-model-config.ts:
// lib/server-model-config.ts
export const ServerProviderSchema = z.object({
name: z.string().min(1), // Display name (shown in UI)
provider: ProviderNameSchema, // e.g. "openai", "anthropic", "ollama"
models: z.array(z.string().min(1)), // Model IDs you want to expose
apiKeyEnv: z.union([z.string(), z.array(z.string())]).optional(),
baseUrlEnv: z.string().optional(),
default: z.boolean().optional(),
})
The loadFlattenedServerModels() function transforms each provider entry into unique model identifiers following the pattern server:${slugified-name}:${modelId}, where the slug is generated by lowercasing the name and replacing non-alphanumeric characters with hyphens. The resulting FlattenedServerModel objects contain resolved apiKeyEnv and baseUrlEnv fields that request handlers use to instantiate SDKs.
Defining Multiple Providers via Environment Variables
Create an ai-models.json file or set AI_MODELS_CONFIG with an array of provider objects:
{
"providers": [
{
"name": "OpenAI Production",
"provider": "openai",
"models": ["gpt-4o", "gpt-4o-mini"],
"apiKeyEnv": "OPENAI_API_KEY_PROD",
"default": true
},
{
"name": "Ollama Local",
"provider": "ollama",
"models": ["llama2:7b"],
"baseUrlEnv": "OLLAMA_BASE_URL"
}
]
}
Export the corresponding environment variables in your deployment environment. The default flag marks the first model of that provider as the server-wide default when no explicit AI_PROVIDER or AI_MODEL is set.
Load Balancing with Multiple API Keys
The apiKeyEnv field accepts either a string or an array of strings. When an array is provided, the system selects the first non-empty value, enabling automatic failover across multiple keys:
{
"name": "OpenAI – Team B",
"provider": "openai",
"models": ["gpt-4o-mini"],
"apiKeyEnv": ["OPENAI_API_KEY_B_1", "OPENAI_API_KEY_B_2"]
}
Admin UI Provider Management
The administrative interface writes provider configurations to settings.json as a JSON string under ADMIN_PROVIDERS. The adminProvidersToConfig() function in lib/admin/providers.ts converts these entries into the standard configuration format, automatically generating environment variable names such as ADMIN_OPENAI_API_KEY_2 or ADMIN_ANTHROPIC_BASE_URL.
When you mark a provider as isDefault: true in the UI, deriveEnvUpdates() writes AI_PROVIDER and AI_MODEL environment variables to designate that model as the server-wide default.
Validation and Security
When adding providers through the UI, the /api/validate-model endpoint in app/api/validate-model/route.ts performs credential validation. This route:
- Blocks SSRF attacks by rejecting private URLs when
isPrivateUrl()detects an internal address andallowPrivateUrls()returns false. - Instantiates the correct SDK (OpenAI, Anthropic, Ollama, etc.) using the supplied credentials.
- Performs a test request using
generateText({ prompt: "Say 'OK'" })to confirm connectivity.
If validation fails, the endpoint returns a user-friendly error before persisting the configuration.
Runtime SDK Instantiation
During chat requests, app/api/chat/route.ts calls findServerModelById() to locate the provider configuration. The handler reads the resolved apiKeyEnv and baseUrlEnv values from process.env to instantiate the correct SDK.
For Ollama deployments, the system supports multiple instances through distinct environment variable mappings:
// app/api/chat/route.ts (excerpt)
const ollamaApiKey = baseUrl
? apiKey || undefined
: apiKey || process.env.OLLAMA_API_KEY || undefined
const ollamaProvider = createOllama({
baseURL: baseUrl || process.env.OLLAMA_BASE_URL || "https://ollama.com/api",
...(ollamaApiKey && { headers: { Authorization: `Bearer ${ollamaApiKey}` } })
})
You can define separate Ollama providers by assigning each a unique baseUrlEnv and apiKeyEnv in your configuration file.
Summary
- Next AI Draw.io uses a layered configuration system in
lib/server-model-config.tsthat prioritizesAI_MODELS_CONFIGenvironment variables, thenai-models.json, then legacy fallbacks. - Provider definitions use the
ServerProviderSchemawith support for customapiKeyEnvandbaseUrlEnvmappings to handle multiple API keys and endpoints per provider. - The
loadFlattenedServerModels()function generates unique IDs in the formatserver:${slugified-name}:${modelId}for each available model. - Admin UI providers are stored in
settings.jsonand converted viaadminProvidersToConfig()inlib/admin/providers.ts, with automatic environment variable generation. - The
/api/validate-modelendpoint enforces SSRF protection viaisPrivateUrl()and validates credentials before persisting new providers. - Runtime handlers in
app/api/chat/route.tsresolve environment variables and instantiate SDKs using the flattened model configuration returned byfindServerModelById().
Frequently Asked Questions
What is the priority order for configuration sources?
The system evaluates sources in three tiers: first the AI_MODELS_CONFIG environment variable, second the ai-models.json file, and third the comma-separated AI_MODEL and AI_PROVIDER fallback. Admin UI configurations stored in settings.json are merged with these sources via loadRawServerModelsConfig() in lib/server-model-config.ts.
How do I configure multiple API keys for the same provider?
Set apiKeyEnv to an array of environment variable names in your ai-models.json configuration. The runtime loader in lib/server-model-config.ts selects the first non-empty value, enabling automatic failover and load balancing across multiple keys for high-throughput deployments.
Can I use private or internal URLs for self-hosted models?
Yes, but only if the server permits private URL access. The validation endpoint in app/api/validate-model/route.ts checks isPrivateUrl() and allowPrivateUrls() before accepting custom base URLs, preventing SSRF attacks against internal networks when private access is disabled.
How does the system handle default model selection?
Mark a provider with "default": true in the JSON configuration file, or set isDefault: true in the admin UI. When using the UI, deriveEnvUpdates() in lib/admin/providers.ts automatically writes AI_PROVIDER and AI_MODEL environment variables to designate that model as the server-wide default when users don't specify an explicit model.
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 →