# Lobe Chat Project Structure: A Deep Dive into the "Roots vs Features" Architecture

> Explore Lobe Chat's project structure organized by roots vs features. Learn how this architecture separates routing from business logic using Next.js, Electron, and a monorepo.

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

---

**Lobe Chat organizes its codebase using a "roots vs features" architecture that separates thin routing entry points from domain-specific business logic, utilizing Next.js 16 for the web layer, Electron for desktop, Zustand for state management, and a monorepo layout with shared packages.**

Lobe Chat is a modern AI chat application built as a Next.js 16 and Electron workspace. Understanding its project structure is essential for contributors extending its functionality. According to the `lobehub/lobe-chat` source code, the codebase follows a deliberate **"roots vs features"** split—where `src/routes/` holds only page segments while business logic and UI live in `src/features/`—maximizing modularity and maintainability.

## Overview of the "Roots vs Features" Architecture

The project employs a strict two-layer separation that keeps routing concerns distinct from implementation details:

- **Roots (Entry Points)**: Thin wrappers in `src/app/` (Next.js app router) and `src/routes/` (SPA page segments) that handle URL mapping and layout composition without containing business logic.
- **Features (Domain Modules)**: Self-contained modules under `src/features/` that encapsulate UI components, hooks, and local state for specific domains like chat, agents, or settings.

This separation is documented in the built-in **spa-routes** skill at [`/.agents/skills/spa-routes/SKILL.md`](https://github.com/lobehub/lobe-chat/blob/main//.agents/skills/spa-routes/SKILL.md), which states: *"This project uses a roots vs features split: `src/routes/` only holds page segments; business logic and UI live in `src/features/` by domain."*

## Directory Layout Breakdown

The repository follows a monorepo structure with clear boundaries between the web application, desktop client, and shared libraries:

```

lobe-chat/
├─ apps/
│   └─ desktop/                # Electron app (main, preload, resources)

├─ packages/
│   ├─ database/               # Drizzle ORM schemas & repositories

│   ├─ agent-runtime/          # Agent execution engine

│   └─ …                       # Other shared libs

├─ src/
│   ├─ app/                    # Next.js 16 app router (pages, layouts, API routes)

│   ├─ routes/                 # SPA route "segments" (thin wrappers)

│   ├─ features/               # Domain-oriented UI components & hooks

│   │   ├─ chat/               # Chat UI, message list, input box

│   │   ├─ agent/              # Agent management UI

│   │   └─ …                   # Other feature folders

│   ├─ store/                  # Zustand stores (video, settings, user)

│   ├─ services/               # Client-side services (auth, analytics)

│   ├─ server/                 # Server-side utilities (middleware, version check)

│   ├─ layout/                 # Global layout providers (theme, i18n, auth)

│   └─ utils/                  # Generic helpers (router, locale, file utils)

├─ public/                     # Static files (videos, images, favicon)

├─ locales/                    # Translation JSON files (zh-TW, en, …)

├─ .github/                    # CI/CD workflows, issue templates

├─ next.config.ts              # Next.js configuration

└─ vite.config.ts              # Vite configuration for SPA parts

```

## Key Architectural Patterns

### Routing Layer Separation

The entry points remain intentionally thin. The `src/app/` directory contains Next.js pages, API routes, and the global layout that wraps the entire web application. Meanwhile, `src/routes/` defines page "segments" (e.g., [`src/routes/chat/page.tsx`](https://github.com/lobehub/lobe-chat/blob/main/src/routes/chat/page.tsx)) that act as pure delegation layers, importing their actual UI from feature modules.

### Feature Module Organization

Each domain maintains its own folder under `src/features/`. A typical feature module exports:
- UI components (e.g., [`Component.tsx`](https://github.com/lobehub/lobe-chat/blob/main/Component.tsx))
- Custom hooks (e.g., [`useFeature.ts`](https://github.com/lobehub/lobe-chat/blob/main/useFeature.ts))
- Local store slices when needed

This structure prevents router files from becoming bloated and allows developers to add new capabilities without modifying routing logic.

### State Management with Zustand

Global application state lives under `src/store/`, implemented using **Zustand** stores. For example, [`src/store/video/store.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/store/video/store.ts) manages video-related state, while `src/store/settings/` handles configuration. These stores are composed and initialized in [`src/layout/GlobalProvider/StoreInitialization.tsx`](https://github.com/lobehub/lobe-chat/blob/main/src/layout/GlobalProvider/StoreInitialization.tsx), ensuring consistent state hydration across the application.

### Monorepo Shared Packages

Reusable code that crosses application boundaries resides in `packages/`:
- `packages/database/` provides Drizzle ORM schemas and repositories
- `packages/agent-runtime/` contains the agent execution engine
- Additional libraries for web crawling, AI providers, etc.

These packages are referenced via the monorepo's `pnpm` workspace configuration, enabling a single source of truth for data models and business logic across web and desktop builds.

### Desktop Integration

The Electron application lives in `apps/desktop/`, containing the main process (`src/main/`), preload scripts (`src/preload/`), and desktop-specific resources. This structure allows the desktop client to share utilities and state management logic with the web codebase while maintaining platform-specific entry points.

## Practical Code Examples

### Importing Feature Components in Routes

Route files act as thin wrappers that delegate rendering to feature modules:

```tsx
// src/routes/chat/page.tsx
import ChatPage from '@/features/chat/ChatPage';

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

```

*(Source: [[`src/routes/chat/page.tsx`](https://github.com/lobehub/lobe-chat/blob/main/src/routes/chat/page.tsx)](https://github.com/lobehub/lobe-chat/blob/canary/src/routes/chat/page.tsx))*

### Consuming Global State

Feature components access shared state through Zustand hooks:

```tsx
// src/features/video/VideoPlayer.tsx
import { useVideoStore } from '@/store/video/store';

export default function VideoPlayer() {
  const { currentVideo, play } = useVideoStore(state => ({
    currentVideo: state.currentVideo,
    play: state.play,
  }));
  return <video src={currentVideo} onPlay={play} controls />;
}

```

*(Source: [[`src/store/video/store.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/store/video/store.ts)](https://github.com/lobehub/lobe-chat/blob/canary/src/store/video/store.ts))*

### Creating a New Feature Module

To add a new domain feature:

```bash

# 1️⃣ Create folder

mkdir -p src/features/notes

# 2️⃣ Add component

cat > src/features/notes/NotesPanel.tsx <<'EOF'
import { useNotesStore } from '@/store/notes';
export default function NotesPanel() {
  const notes = useNotesStore(s => s.list);
  return <div>{notes.map(n => <p key={n.id}>{n.content}</p>)}</div>;
}
EOF

# 3️⃣ Export from feature index

echo "export { default as NotesPanel } from './NotesPanel';" > src/features/notes/index.ts

```

The new panel can then be imported anywhere in the application:

```tsx
import { NotesPanel } from '@/features/notes';

```

### Accessing Shared Packages

Database models and utilities are imported from the monorepo packages:

```ts
import { db } from '@lobehub/database';
import { ChatMessage } from '@lobehub/database/models';

async function saveMessage(msg: ChatMessage) {
  await db.insert(ChatMessage).values(msg);
}

```

*(Source: [[`packages/database/README.md`](https://github.com/lobehub/lobe-chat/blob/main/packages/database/README.md)](https://github.com/lobehub/lobe-chat/blob/canary/packages/database/README.md))*

## Critical Files and Their Roles

Several configuration and provider files serve as the backbone of the architecture:

- **[`next.config.ts`](https://github.com/lobehub/lobe-chat/blob/main/next.config.ts)**: Configures Next.js with rewrites, image domains, and i18n settings.
- **[`vite.config.ts`](https://github.com/lobehub/lobe-chat/blob/main/vite.config.ts)**: Sets up Vite for SPA parts, handling SSR and path aliasing.
- **[`src/layout/GlobalProvider/AppTheme.tsx`](https://github.com/lobehub/lobe-chat/blob/main/src/layout/GlobalProvider/AppTheme.tsx)**: Provides Ant Design theme context and dark-mode handling.
- **[`src/layout/GlobalProvider/StoreInitialization.tsx`](https://github.com/lobehub/lobe-chat/blob/main/src/layout/GlobalProvider/StoreInitialization.tsx)**: Initializes all Zustand stores when the application starts.
- **`src/features/*/index.ts`**: Public re-export barrels for each feature module, establishing clean import contracts.
- **[`apps/desktop/main/index.ts`](https://github.com/lobehub/lobe-chat/blob/main/apps/desktop/main/index.ts)**: Electron main process entry point managing window creation and IPC communication.
- **[`packages/database/src/index.ts`](https://github.com/lobehub/lobe-chat/blob/main/packages/database/src/index.ts)**: Exposes database models and utilities to the entire monorepo.

## Summary

- Lobe Chat uses a **"roots vs features"** split where `src/routes/` contains only thin page segments and `src/features/` holds domain-specific business logic.
- **Next.js 16** powers the web layer in `src/app/`, while **Electron** lives in `apps/desktop/`.
- **Zustand** stores in `src/store/` manage global state, initialized via [`StoreInitialization.tsx`](https://github.com/lobehub/lobe-chat/blob/main/StoreInitialization.tsx).
- **Monorepo packages** in `packages/` share database schemas, agent runtimes, and utilities across applications.
- Route files delegate rendering to feature modules, keeping routing logic decoupled from UI implementation.

## Frequently Asked Questions

### What is the difference between `src/app/` and `src/routes/` in Lobe Chat?

`src/app/` contains the Next.js 16 app router pages, API routes, and global layouts that wrap the entire application. `src/routes/` serves as the SPA route segment layer, holding thin page wrappers that import their actual UI components from `src/features/`. This separation ensures routing files remain lightweight while complex business logic resides in dedicated feature modules.

### How does Lobe Chat manage global state across the application?

The project uses **Zustand** for state management, with individual stores organized under `src/store/` by domain (e.g., [`src/store/video/store.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/store/video/store.ts), `src/store/settings/`). These stores are composed and initialized in [`src/layout/GlobalProvider/StoreInitialization.tsx`](https://github.com/lobehub/lobe-chat/blob/main/src/layout/GlobalProvider/StoreInitialization.tsx), ensuring consistent state availability throughout the component tree without prop drilling.

### Where should new features be added in the Lobe Chat codebase?

New capabilities belong in `src/features/` under a domain-specific folder (e.g., `src/features/notes/`). Each feature should export its components and hooks through an [`index.ts`](https://github.com/lobehub/lobe-chat/blob/main/index.ts) barrel file. The feature can then be imported into route files in `src/routes/` or `src/app/` without modifying the router's structural logic, maintaining the "roots vs features" architectural boundary.

### How are database models shared between the web and desktop applications?

Database schemas and repositories live in `packages/database/` as part of the monorepo structure. Both the Next.js application and Electron desktop client import these models using the `@lobehub/database` workspace alias. This setup ensures data consistency across platforms while avoiding code duplication between the web and desktop builds.