How to Customize Available Models in NextChat Using the CUSTOM_MODELS Environment Variable

Set the CUSTOM_MODELS environment variable to add, remove, or rename models in NextChat without modifying any source code.

The CUSTOM_MODELS environment variable in ChatGPTNextWeb/NextChat provides a declarative way to control which AI models appear in the web interface. By configuring this variable, administrators can override the default model list defined in app/constant.ts, hide specific providers, or register entirely custom deployments. Changes take effect immediately after a server restart, reshaping the model selector UI without requiring code changes.

Server-Side Configuration Loading

When the NextChat server boots, it reads the CUSTOM_MODELS variable from the environment and stores the raw string in the server configuration object.

In app/config/server.ts (lines 140–149), the initialization logic captures the variable:

let customModels = process.env.CUSTOM_MODELS ?? "";

customModels,          // later returned as part of the server config

This raw string is then passed to the model-handling utilities that merge it with the DEFAULT_MODELS constant.

Model Table Generation and Parsing

The core parsing logic resides in app/utils/model.ts (lines 77–132) inside the collectModelTable function. This utility splits the CUSTOM_MODELS string by commas and processes each token to build the final model table.

The parser interprets each entry according to specific prefix operators:

  • +modelAdd a model or enable an existing one that is hidden by default
  • -modelRemove or hide a model from the selector
  • name=displayNameRename the entry in the UI while preserving the internal ID
  • model@provider – Target a specific provider (e.g., Azure, ByteDance) for the deployment

The special token all toggles visibility for every default model at once. As implemented in lines 86–92 of app/utils/model.ts:

if (name === "all") {
  Object.values(modelTable).forEach(
    (model) => (model.available = available),
  );
}

When a supplied name does not match any existing model in DEFAULT_MODELS, the code creates a brand-new custom entry (lines 115–132):

const provider = customProvider(customProviderName || customModelName);
modelTable[`${customModelName}@${provider?.id}`] = {
  name: customModelName,
  displayName: displayName || customModelName,
  available,
  provider,
  sorted: CustomSeq.next(`${customModelName}@${provider?.id}`),
};

The resulting model list is cached and sent to the frontend, where the model selector displays only entries marked as available.

CUSTOM_MODELS Syntax Patterns

The variable accepts a comma-separated list of directives. The parser processes each segment sequentially, so order matters when using all or overlapping rules.

Add or Enable Models

Use the + prefix to append models to the selector or force-enable existing entries:

CUSTOM_MODELS="+llama,+claude-2"

This adds llama and claude-2 alongside the default models.

Hide Default Models

Use the - prefix to remove specific models from the UI:

CUSTOM_MODELS="-gpt-3.5-turbo"

This hides GPT-3.5 Turbo while keeping other defaults visible.

Rename Models for Display

Use the = operator to change the human-readable label without altering the API identifier:

CUSTOM_MODELS="gpt-4-1106-preview=gpt-4-turbo"

The model retains its internal ID gpt-4-1106-preview but appears as gpt-4-turbo in the dropdown.

Bulk Operations with "all"

Target all default models simultaneously, then apply exceptions:

CUSTOM_MODELS="+all,-gpt-4"

This enables every default model, then disables any model matching gpt-4.

Provider-Specific Deployments

Append @provider to route requests to specific backends like Azure or ByteDance:

Azure deployment example:

CUSTOM_MODELS="+gpt-3.5-turbo@Azure=gpt35"

This displays gpt35(Azure) in the UI and uses the Azure provider configuration.

ByteDance endpoint example:

CUSTOM_MODELS="+Doubao-lite-4k@bytedance=ep-xxxx"

This appears as Doubao-lite-4k(ByteDance) and utilizes the specified deployment ID ep-xxxx.

Complete List Replacement

Disable every built-in model and define a single custom entry:

CUSTOM_MODELS="-all,+my-model@openai=MyModel"

This results in a selector containing only MyModel provided by OpenAI.

Implementation Reference

The following files constitute the complete pipeline for model customization:

  • app/config/server.ts – Reads CUSTOM_MODELS from process.env and injects it into the server config (lines 140–149)
  • app/utils/model.ts – Parses the string, merges it with defaults via collectModelTable, and constructs the final model table (lines 77–132)
  • app/constant.ts – Defines the DEFAULT_MODELS array that serves as the baseline for all modifications

Summary

  • CUSTOM_MODELS controls the NextChat model selector via environment configuration alone
  • Syntax operators: + adds, - removes, = renames, and @ specifies providers
  • Special keyword: all modifies every default model simultaneously for bulk enable/disable operations
  • Custom models: Unknown model names trigger automatic creation of new entries with generated provider metadata
  • No rebuild required: Changes apply after a simple server restart since the variable is evaluated at runtime in app/config/server.ts

Frequently Asked Questions

Do I need to rebuild the Docker image after changing CUSTOM_MODELS?

No. Because NextChat reads CUSTOM_MODELS from process.env at runtime in app/config/server.ts, you only need to restart the container. Update your .env file or Docker Compose configuration, then run docker-compose restart to apply changes.

What happens if I specify a model name that does not exist in the default list?

According to the logic in app/utils/model.ts (lines 115–132), NextChat automatically creates a custom model entry for unknown names. It generates a provider object using customProvider(), assigns a display name (defaulting to the model name if no = is provided), and adds it to the model table with a unique sort sequence.

How do I target my Azure OpenAI deployment specifically?

Use the @Azure provider suffix combined with the = display name operator. For example, +gpt-3.5-turbo@Azure=my-deployment-name routes requests through the Azure provider while showing my-deployment-name(Azure) in the UI. This syntax is parsed in app/utils/model.ts by splitting on @ and = respectively.

Can I both add a new model and hide a default one in the same variable?

Yes. The parser processes directives sequentially from left to right. For example, CUSTOM_MODELS="+custom-llama,-gpt-3.5-turbo" first adds the custom model, then removes the default GPT-3.5 Turbo entry from the selector.

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 →