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:

  1. User-provided overrides.apiKey (highest priority)
  2. Custom environment variable(s) from overrides.apiKeyEnv
  3. 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_A or OPENAI_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 apiKeyEnv and baseUrlEnv in ai-models.json or the AI_MODELS_CONFIG environment variable
  • Load-balance multiple keys by providing an array of environment variable names, which resolveApiKey selects from randomly
  • Validate credentials automatically through validateProviderCredentials before model instantiation
  • Override at runtime via ClientOverrides in components/provider-credentials-fields.tsx for user-specific credentials
  • Route to private endpoints by specifying custom baseUrlEnv values that resolve through resolveBaseURL

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →