# How to Add New Features or Models to Lobe Chat: A Complete Developer Guide

> Learn how to add new features or models to Lobe Chat. Our developer guide covers creating ModelProviderCards for backend support and React components for UI functionality.

- Repository: [LobeHub/lobe-chat](https://github.com/lobehub/lobe-chat)
- Tags: how-to-guide
- Published: 2026-03-03

---

**Adding new features or models to Lobe Chat involves creating a `ModelProviderCard` in `packages/model-bank/src/modelProviders/` for backend model support, or building React components in `src/features/` for UI functionality, then wiring them through the Zustand store and i18n system.**

Lobe Chat is a modern AI chat application built by lobehub that separates model provider definitions from UI features through a type-safe TypeScript architecture. Whether you need to integrate a new LLM provider or build a custom interface component, understanding how to add new features or models to Lobe Chat requires navigating its provider card system, state management, and React component structure.

## Understanding Lobe Chat's Architecture

Lobe Chat's architecture separates **model providers** (the back-end definitions of AI models) from **UI features** (React components that surface functionality). Adding a new model or a new front-end feature follows a predictable, type-safe flow:

1. **Model side** – create a provider card, register it, and expose it through the parsing utilities.
2. **State side** – the provider list is loaded into the Zustand store so the UI can enumerate it.
3. **UI side** – build a feature component, add a route (if needed), and optionally expose i18n strings.

All of these steps are pure TypeScript/React; no runtime code execution is required.

## Adding a New Model Provider

### Step 1: Define the Provider Card

Each provider is described by a **`ModelProviderCard`** (type defined in [`packages/types/src/llm.ts`](https://github.com/lobehub/lobe-chat/blob/main/packages/types/src/llm.ts)). It contains the provider `id`, `displayName`, `description`, and an array of `chatModels`.

```ts
// packages/types/src/llm.ts
export interface ModelProviderCard {
  id: string;
  displayName: string;
  description?: string;
  chatModels: ChatModelCard[];
  // …other optional fields (e.g., `enabled`, `icon`)
}

```

Create a provider file under `packages/model-bank/src/modelProviders/`. Use an existing provider as a template (e.g., [`openai.ts`](https://github.com/lobehub/lobe-chat/blob/main/openai.ts)):

```ts
// packages/model-bank/src/modelProviders/mynewprovider.ts
import type { ModelProviderCard } from '@/types/llm';
import { createChatModel } from '@/utils/model';

const MyNewProvider: ModelProviderCard = {
  id: 'mynewprovider',
  displayName: 'My New Provider',
  description: 'A custom LLM provider for demo purposes',
  chatModels: [
    createChatModel({
      id: 'my-model-1',
      displayName: 'My Model 1',
      // token limit, abilities, etc.
      contextWindowTokens: 4096,
      abilities: {
        reasoning: true,
        vision: false,
        functionCall: true,
        files: false,
      },
    }),
    // …add more models if needed
  ],
};

export default MyNewProvider;

```

The helper `createChatModel` lives in [`packages/model-bank/src/utils/model.ts`](https://github.com/lobehub/lobe-chat/blob/main/packages/model-bank/src/utils/model.ts) (you can also construct the object manually).

### Step 2: Register the Provider

Export the provider in the central index:

```ts
// packages/model-bank/src/modelProviders/index.ts
import MyNewProvider from './mynewprovider';
/* …other imports… */

export const DEFAULT_MODEL_PROVIDER_LIST = [
  /* existing providers … */
  MyNewProvider, // ← add here
];

```

Run the type-checking script (`bun run type-check`) to ensure the new card complies with `ModelProviderCard`.

### Step 3: Verify Model Parsing

When a user enters a model selector string (e.g., `gpt-4<8192:vision>`), Lobe Chat parses it with [`parseModels.ts`](https://github.com/lobehub/lobe-chat/blob/main/parseModels.ts). The new provider's models are automatically recognized as long as they appear in `DEFAULT_MODEL_PROVIDER_LIST`.

```ts
// src/utils/server/parseModels.ts
export const parseModelString = async (
  providerId: string,
  modelString: string = '',
  withDeploymentName = false,
) => {
  // …
  const modelType = await getModelPropertyWithFallback<AiModelType>(
    id,
    'type',
    providerId,
  );
  // …
};

```

No further changes are needed – the parser looks up the model type via `@lobechat/model-runtime`, which in turn reads the provider card you added.

### Step 4: State Integration

The provider list is loaded into the **Zustand** store (`aiProvider` slice). Adding a new provider automatically makes it selectable in the UI.

```ts
// src/store/aiInfra/slices/aiProvider/action.ts
const [{ LOBE_DEFAULT_MODEL_LIST }, { DEFAULT_MODEL_PROVIDER_LIST }] =
  await Promise.all([
    import('model-bank'),
    import('model-bank/modelProviders'),
  ]);
// …
const enabledAiProviders: EnabledProvider[] = DEFAULT_MODEL_PROVIDER_LIST.filter(
  (p) => p.enabled !== false,
);

```

## Adding a New Front-End Feature

### Step 1: Create the Feature Component

All UI pieces live under `src/features/`. A feature typically consists of a React component (TSX), optional hooks, and i18n entries.

```tsx
// src/features/MyNewFeature.tsx
import React from 'react';
import { Card, Button } from 'antd';
import { useTranslation } from 'react-i18next';
import { useChatStore } from '@/store/chat';

export const MyNewFeature = () => {
  const { t } = useTranslation('default');
  const startChat = useChatStore((s) => s.startChat);

  return (
    <Card title={t('myNewFeature.title')}>
      <p>{t('myNewFeature.description')}</p>
      <Button type="primary" onClick={() => startChat('mynewprovider', 'my-model-1')}>
        {t('myNewFeature.startButton')}
      </Button>
    </Card>
  );
};

```

### Step 2: Add Internationalization

Add i18n strings under `src/locales/default/`:

```ts
// src/locales/default/myNewFeature.ts
export default {
  title: 'Demo Feature',
  description: 'A quick way to start a chat with My New Model.',
  startButton: 'Start Demo Chat',
};

```

Re-export it in the locale index:

```ts
// src/locales/default/index.ts
import myNewFeature from './myNewFeature';
export default {
  /* …existing imports… */
  myNewFeature,
};

```

### Step 3: Wire Into Routing

If the feature should have its own page, add a folder under `src/routes/(main)/`:

```tsx
// src/routes/(main)/my-demo/page.tsx
import { MyNewFeature } from '@/features/MyNewFeature';

export default function Page() {
  return <MyNewFeature />;
}

```

The route automatically picks up the Next.js file-system routing.

### Step 4: Testing Your Feature

Lobe Chat uses **Vitest** for unit tests. Add a test under [`src/features/__tests__/MyNewFeature.test.tsx`](https://github.com/lobehub/lobe-chat/blob/main/src/features/__tests__/MyNewFeature.test.tsx):

```ts
import { render, screen, fireEvent } from '@testing-library/react';
import { MyNewFeature } from '@/features/MyNewFeature';
import { useChatStore } from '@/store/chat';

vi.mock('@/store/chat', () => ({
  useChatStore: vi.fn(() => ({
    startChat: vi.fn(),
  })),
}));

test('starts chat with the new model', () => {
  render(<MyNewFeature />);
  fireEvent.click(screen.getByRole('button'));
  expect(useChatStore().startChat).toHaveBeenCalledWith('mynewprovider', 'my-model-1');
});

```

Run the test: `bunx vitest src/features/__tests__/MyNewFeature.test.tsx`.

## Complete Integration Example

Below is a minimal, end-to-end snippet showing the three main files you need to modify/create.

```ts
// packages/model-bank/src/modelProviders/mynewprovider.ts
import type { ModelProviderCard } from '@/types/llm';
import { createChatModel } from '@/utils/model';

const MyNewProvider: ModelProviderCard = {
  id: 'mynewprovider',
  displayName: 'My New Provider',
  chatModels: [
    createChatModel({
      id: 'my-model-1',
      displayName: 'My Model 1',
      contextWindowTokens: 4096,
      abilities: { reasoning: true, functionCall: true },
    }),
  ],
};

export default MyNewProvider;

```

```ts
// packages/model-bank/src/modelProviders/index.ts (excerpt)
import MyNewProvider from './mynewprovider';
/* …existing imports… */

export const DEFAULT_MODEL_PROVIDER_LIST = [
  /* …existing providers… */
  MyNewProvider,
];

```

```tsx
// src/features/MyNewFeature.tsx
import React from 'react';
import { Card, Button } from 'antd';
import { useTranslation } from 'react-i18next';
import { useChatStore } from '@/store/chat';

export const MyNewFeature = () => {
  const { t } = useTranslation('default');
  const startChat = useChatStore((s) => s.startChat);

  return (
    <Card title={t('myNewFeature.title')}>
      <p>{t('myNewFeature.description')}</p>
      <Button type="primary" onClick={() => startChat('mynewprovider', 'my-model-1')}>
        {t('myNewFeature.startButton')}
      </Button>
    </Card>
  );
};

```

After adding these files, run `bun run type-check` to verify TypeScript compliance, then start the dev server with `bun dev` to see the new provider and feature in action.

## Key Files Reference

| Area | File | Purpose |
|------|------|---------|
| **Model definition** | `packages/model-bank/src/modelProviders/<provider>.ts` | Holds the `ModelProviderCard` for each provider. |
| **Provider registry** | [`packages/model-bank/src/modelProviders/index.ts`](https://github.com/lobehub/lobe-chat/blob/main/packages/model-bank/src/modelProviders/index.ts) | `DEFAULT_MODEL_PROVIDER_LIST` is the source of truth for all providers. |
| **Model parsing** | [`src/utils/server/parseModels.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/utils/server/parseModels.ts) | Translates user-entered strings into concrete model objects. |
| **State loading** | [`src/store/aiInfra/slices/aiProvider/action.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/store/aiInfra/slices/aiProvider/action.ts) | Pulls the provider list into the Zustand store. |
| **Feature component** | `src/features/<Feature>.tsx` | UI implementation of a new capability. |
| **Routing** | `src/routes/(main)/<slug>/page.tsx` | Optional page wrapper for a feature. |
| **i18n** | `src/locales/default/<feature>.ts` | Adds localized strings for the UI. |
| **Tests** | `src/**/*.test.tsx` | Vitest unit tests for components and logic. |

## Summary

- **Model providers** are defined as `ModelProviderCard` objects in `packages/model-bank/src/modelProviders/` and exported via `DEFAULT_MODEL_PROVIDER_LIST` in the index file.
- **Model parsing** happens automatically through [`src/utils/server/parseModels.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/utils/server/parseModels.ts) once the provider is registered, requiring no manual parser updates.
- **State management** integrates new providers via the Zustand store in [`src/store/aiInfra/slices/aiProvider/action.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/store/aiInfra/slices/aiProvider/action.ts), making them immediately selectable in the UI.
- **Front-end features** are React components in `src/features/` that consume the store and require i18n entries in `src/locales/default/` for localization.
- **Testing** uses Vitest; run `bun run type-check` and `bunx vitest` to validate changes before deployment.

## Frequently Asked Questions

### Do I need to modify the database schema to add a new provider?

No, Lobe Chat uses a runtime provider card system where models are defined in TypeScript files under `packages/model-bank/src/modelProviders/`. The `DEFAULT_MODEL_PROVIDER_LIST` array is loaded into the Zustand store at runtime, so no database migrations are required to add or update model providers.

### How do I test a new model provider without API credentials?

You can verify the provider integration using `bun run type-check` to ensure TypeScript compliance and run `bunx vitest` to execute unit tests. The provider will appear in the UI's model selector even without valid API keys, allowing you to test the parsing logic and state integration; only the actual chat completion will fail when the backend attempts to call the provider's API.

### Can I add a feature without adding a new provider?

Yes, front-end features in `src/features/` are completely independent of the model provider system. You can build React components that utilize existing models through the `useChatStore` hook or implement entirely new UI capabilities such as dashboards, tools, or widgets without modifying any files in `packages/model-bank/`.

### What testing framework does Lobe Chat use?

Lobe Chat uses **Vitest** for unit testing. Test files are typically co-located with source files or placed in `__tests__` directories throughout the `src/` folder. You can run the full test suite with `bunx vitest` or target specific files to validate that new features and providers integrate correctly with existing state management and UI components.