How to Integrate a New AI Provider into NextChat: A Complete Developer Guide

Integrating a new AI provider into NextChat requires extending two enums in app/constant.ts, creating an API route handler in app/api/, and wiring the provider mapping in app/client/api.ts to route requests through the generic ClientApi architecture.

NextChat (formerly ChatGPT Next Web) is built on a clean abstraction layer that treats every LLM vendor as a pluggable service. The open-source codebase maintained by ChatGPTNextWeb uses a dual-enum pattern—ServiceProvider for UI logic and ModelProvider for API routing—to decouple the frontend from backend implementations. This architecture allows developers to add custom AI backends like Groq, Mistral, or private endpoints without modifying core chat logic.

Understanding the Provider Architecture

NextChat abstracts every LLM behind two distinct concepts defined in app/constant.ts:

Concept Location Purpose
ServiceProvider enum ServiceProvider The logical vendor name displayed in the UI (e.g., OpenAI, Google).
ModelProvider enum ModelProvider The internal identifier that ClientApi uses to determine request shape and base URL.

When you integrate a new provider, you bridge these two enums through four layers: constant definitions, HTTP proxy routes, client instantiation, and optional UI customization.

Step-by-Step Integration Guide

Step 1: Extend the Enums in app/constant.ts

Add your provider to both enums to register it with the system. For this example, we will add a fictional provider called FooAI.

// app/constant.ts
export enum ServiceProvider {
  OpenAI = "OpenAI",
  Google = "Google",
  // ... existing providers
  FooAI = "FooAI",               // <─ Add here
}

export enum ModelProvider {
  GPT = "GPT",
  GeminiPro = "GeminiPro",
  // ... existing providers  
  FooAI = "FooAI",               // <─ And here
}

Reference: See the ServiceProvider definition and ModelProvider implementation in [app/constant.ts](https://github.com/ChatGPTNextWeb/NextChat/blob/main/app/constant.ts).

Step 2: Add Connection Constants

Define the endpoint configuration object immediately after the enums. Follow the naming convention used by existing providers like OpenaiPath or Google.

// app/constant.ts
export const FooAI = {
  ExampleEndpoint: "https://api.fooai.com",
  ChatPath: "v1/chat/completions",    // Adjust to match vendor API spec
  ApiKey: process.env.FOOAI_API_KEY,  // Optional: direct env reference
};

Reference: Example constant blocks for other vendors are located at lines 78-100 of [app/constant.ts](https://github.com/ChatGPTNextWeb/NextChat/blob/main/app/constant.ts#L78-L100).

Step 3: Create the API Route Handler

Create a new file at app/api/fooai.ts (or app/api/fooai/route.ts depending on your App Router structure). This file acts as an edge proxy between the client and the third-party API.

// app/api/fooai.ts
import { NextRequest, NextResponse } from "next/server";
import { auth } from "./auth";
import { getServerSideConfig } from "@/app/config/server";
import { ModelProvider, FooAI } from "@/app/constant";
import { prettyObject } from "@/app/utils/format";

const serverConfig = getServerSideConfig();

export async function handle(
  req: NextRequest,
  { params }: { params: { path: string[] } },
) {
  console.log("[FooAI Route] params ", params);
  
  if (req.method === "OPTIONS") {
    return NextResponse.json({ body: "OK" }, { status: 200 });
  }

  const authResult = auth(req, ModelProvider.FooAI);
  if (authResult.error) {
    return NextResponse.json(authResult, { status: 401 });
  }

  try {
    const response = await request(req);
    return response;
  } catch (e) {
    console.error("[FooAI] ", e);
    return NextResponse.json(prettyObject(e));
  }
}

export const GET = handle;
export const POST = handle;
export const runtime = "edge";

async function request(req: NextRequest) {
  const controller = new AbortController();
  
  const apiKey = req.headers.get("Authorization")?.replace("Bearer ", "") ?? 
                 serverConfig.fooaiApiKey;
  if (!apiKey) {
    throw new Error("Missing FOOAI_API_KEY");
  }

  const baseUrl = FooAI.ExampleEndpoint;
  const path = req.nextUrl.pathname.replaceAll("/api/fooai", "");
  const fetchUrl = `${baseUrl}/${FooAI.ChatPath}${path}`;

  const fetchOptions: RequestInit = {
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${apiKey}`,
    },
    method: req.method,
    body: req.body,
    redirect: "manual",
    // @ts-ignore
    duplex: "half",
    signal: controller.signal,
  };

  const res = await fetch(fetchUrl, fetchOptions);
  const newHeaders = new Headers(res.headers);
  newHeaders.delete("www-authenticate");
  newHeaders.set("X-Accel-Buffering", "no");

  return new Response(res.body, {
    status: res.status,
    statusText: res.statusText,
    headers: newHeaders,
  });
}

Reference: The openai.ts handler at [app/api/openai.ts](https://github.com/ChatGPTNextWeb/NextChat/blob/main/app/api/openai.ts#L29-L73) provides the canonical implementation pattern.

Step 4: Register the Client API Mapping

Wire the ServiceProvider to the ModelProvider in the client factory function so the frontend knows which API class to instantiate.

// app/client/api.ts
export function getClientApi(provider: ServiceProvider): ClientApi {
  switch (provider) {
    case ServiceProvider.OpenAI:
      return new ClientApi(ModelProvider.GPT);
    case ServiceProvider.Google:
      return new ClientApi(ModelProvider.GeminiPro);
    case ServiceProvider.FooAI:
      return new ClientApi(ModelProvider.FooAI);   // <─ Map new provider
    default:
      return new ClientApi(ModelProvider.GPT);
  }
}

Reference: The getClientApi switch statement is defined at lines 68-98 of [app/client/api.ts](https://github.com/ChatGPTNextWeb/NextChat/blob/main/app/client/api.ts#L68-L98).

Step 5: Configure Environment Variables

Add the required secrets to your environment configuration. NextChat automatically ingests *_API_KEY and *_ENDPOINT patterns through getServerSideConfig.


# .env.local or .env.template

FOOAI_API_KEY=your_fooai_api_key_here
FOOAI_ENDPOINT=https://api.fooai.com

No additional code changes are required for environment variable parsing; the existing getServerSideConfig utility in app/config/server.ts handles dynamic key ingestion.

Step 6: (Optional) Customize the UI

The provider dropdown in the Model Config dialog populates automatically from the ServiceProvider enum via the groupModels helper in app/utils/model.ts. If you want to add a custom icon or provider description, modify app/components/model-config.tsx:

// app/components/model-config.tsx
{Object.keys(groupModels).map((providerName) => (
  <optgroup label={providerName} key={providerName}>
    {groupModels[providerName].map((v) => (
      <option
        value={`${v.name}@${v.provider?.providerName}`}
        key={v.name}
      >
        {v.displayName} ({v.provider?.providerName})
      </option>
    ))}
  </optgroup>
))}

Reference: See the model configuration component at [app/components/model-config.tsx](https://github.com/ChatGPTNextWeb/NextChat/blob/main/app/components/model-config.tsx#L41-L45).

Key Files for Provider Integration

File Purpose Link
app/constant.ts Defines ServiceProvider, ModelProvider enums and endpoint constants [constant.ts](https://github.com/ChatGPTNextWeb/NextChat/blob/main/app/constant.ts)
app/client/api.ts Contains getClientApi factory that maps providers to client instances [api.ts](https://github.com/ChatGPTNextWeb/NextChat/blob/main/app/client/api.ts)
app/api/<provider>.ts HTTP proxy implementation; copy openai.ts as a template [openai.ts](https://github.com/ChatGPTNextWeb/NextChat/blob/main/app/api/openai.ts)
app/utils/model.ts Helper functions for parsing model strings like "gpt-4o@OpenAI" [model.ts](https://github.com/ChatGPTNextWeb/NextChat/blob/main/app/utils/model.ts)
app/components/model-config.tsx UI component rendering the provider selection dropdown [model-config.tsx](https://github.com/ChatGPTNextWeb/NextChat/blob/main/app/components/model-config.tsx)

Summary

  • Extend both enums in app/constant.ts to register the provider name with the system architecture.
  • Define endpoint constants (base URL and chat path) to configure the HTTP proxy target.
  • Create an API route in app/api/ that authenticates requests and proxies them to the vendor endpoint using the Edge Runtime.
  • Map the provider in getClientApi within app/client/api.ts to link the UI selection to the correct backend handler.
  • Set environment variables following the PROVIDER_API_KEY naming convention for automatic server-side configuration ingestion.

Frequently Asked Questions

Do I need to modify the frontend components to show the new provider in the dropdown?

No. The Model Config dialog automatically builds the provider list from the ServiceProvider enum in app/constant.ts. As long as you add your provider to that enum, it appears in the UI immediately without touching React components.

Can I support multiple models from the same new provider?

Yes. The ClientApi class accepts a ModelProvider value, and the groupModels utility in app/utils/model.ts aggregates models by their providerName property. Simply ensure your models specify the new ServiceProvider in their definition, and they will group correctly under your provider's header in the UI.

What authentication methods does the API route support?

The example above uses Bearer token authentication passed via the Authorization header, which is the standard for most OpenAI-compatible APIs. However, you can modify the request function in your API route to implement API key headers, query parameters, or custom authentication schemes required by your specific provider.

Is the Edge Runtime mandatory for the API routes?

Yes. NextChat API routes export runtime = "edge" to ensure requests execute at the edge for optimal latency. Your proxy implementation must use Web-standard Request and Response objects compatible with the Edge Runtime, avoiding Node.js-specific modules like fs or http.

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 →