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

> Learn to integrate a new AI provider into NextChat with this developer guide. Extend enums, create API routes, and map providers for seamless integration.

- Repository: [NextChat/NextChat](https://github.com/ChatGPTNextWeb/NextChat)
- Tags: how-to-guide
- Published: 2026-02-28

---

**Integrating a new AI provider into NextChat requires extending two enums in [`app/constant.ts`](https://github.com/ChatGPTNextWeb/NextChat/blob/main/app/constant.ts), creating an API route handler in `app/api/`, and wiring the provider mapping in [`app/client/api.ts`](https://github.com/ChatGPTNextWeb/NextChat/blob/main/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`](https://github.com/ChatGPTNextWeb/NextChat/blob/main/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`.

```typescript
// 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)](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`.

```typescript
// 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)](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`](https://github.com/ChatGPTNextWeb/NextChat/blob/main/app/api/fooai.ts) (or [`app/api/fooai/route.ts`](https://github.com/ChatGPTNextWeb/NextChat/blob/main/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.

```typescript
// 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`](https://github.com/ChatGPTNextWeb/NextChat/blob/main/openai.ts) handler at [[`app/api/openai.ts`](https://github.com/ChatGPTNextWeb/NextChat/blob/main/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.

```typescript
// 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)](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`.

```bash

# .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`](https://github.com/ChatGPTNextWeb/NextChat/blob/main/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`](https://github.com/ChatGPTNextWeb/NextChat/blob/main/app/utils/model.ts). If you want to add a custom icon or provider description, modify [`app/components/model-config.tsx`](https://github.com/ChatGPTNextWeb/NextChat/blob/main/app/components/model-config.tsx):

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

## Summary

- **Extend both enums** in [`app/constant.ts`](https://github.com/ChatGPTNextWeb/NextChat/blob/main/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`](https://github.com/ChatGPTNextWeb/NextChat/blob/main/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`](https://github.com/ChatGPTNextWeb/NextChat/blob/main/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`](https://github.com/ChatGPTNextWeb/NextChat/blob/main/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`.