# Open Notebook Three-Tier Architecture: Next.js Frontend, FastAPI Backend, and SurrealDB Database

> Explore the three-tier architecture of Open Notebook, featuring a Next.js frontend, FastAPI backend, and SurrealDB database for efficient data management and built-in vector search.

- Repository: [Luis Novo/open-notebook](https://github.com/lfnovo/open-notebook)
- Tags: architecture
- Published: 2026-07-01

---

**Open Notebook implements a classic three-tier architecture with Next.js handling the presentation layer, FastAPI powering the application logic, and SurrealDB managing graph-based data persistence with built-in vector search.**

The open-source project `lfnovo/open-notebook` structures its codebase as a clean separation of concerns across three distinct tiers. This architecture enables independent scaling of the React-based user interface, Python-based AI workflow engine, and graph database backend. Understanding how these layers interact reveals why the system can handle concurrent AI operations while maintaining responsive real-time updates.

## Presentation Tier: Next.js Frontend

Located in `/frontend/`, the presentation tier uses **Next.js** with React 19 to render notebooks, sources, notes, chat interfaces, podcasts, and search functionality. According to [`frontend/CLAUDE.md`](https://github.com/lfnovo/open-notebook/blob/main/frontend/CLAUDE.md), the frontend relies on **Zustand** for state management and **TanStack Query** (React Query) for server state synchronization. UI components come from **shadcn/ui** styled with Tailwind CSS, creating a cohesive design system without custom CSS overhead.

### State Management and Data Fetching

Data fetching happens through TanStack Query hooks that communicate with the FastAPI backend running on port 5055. The `apiClient` instance configures the base URL via environment variables, typically defaulting to `http://localhost:5055`. This setup automatically handles caching, background refetching, and optimistic updates without manual Redux boilerplate.

### UI Component Architecture

The interface builds upon shadcn/ui primitives, providing accessible and customizable components for complex notebook interfaces. Tailwind CSS handles all styling, ensuring consistent spacing and typography across the application while keeping bundle sizes minimal through tree-shaking.

## Application Tier: FastAPI Backend

The middle layer resides in `/api/` and `/open_notebook/`, implementing a **FastAPI** 0.104+ application that exposes REST endpoints on **port 5055**. This tier handles all business logic including **LangGraph** workflows for content ingestion, chat operations, search-and-synthesis pipelines, and content transformations. The architecture uses **Esperanto** for multi-provider AI orchestration, supporting OpenAI, Anthropic, and Ollama through a unified interface.

### Async-First API Design

Every database call, graph operation, and external AI request uses Python's `async`/`await` patterns, preventing blocking during I/O operations. In [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py), the application configures CORS middleware to mirror allowed origins and implements centralized error handling alongside optional password protection middleware. The async design allows FastAPI to handle thousands of concurrent connections without thread pool exhaustion.

### LangGraph Workflow Engine

Complex operations execute as LangGraph workflows defined in modules like [`open_notebook/graphs/ask.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/ask.py). These graphs orchestrate multi-step processes such as retrieving relevant sources from SurrealDB, embedding content for semantic search, and synthesizing responses through LLM providers. The workflow engine maintains state across asynchronous operations, enabling long-running AI processes without blocking API requests.

## Data Tier: SurrealDB Database

**SurrealDB** operates on **port 8000** as a graph database with native vector search capabilities. It stores core entities including `Notebook`, `Source`, `Note`, `ChatSession`, and `Credential` records while maintaining relationships like "source-to-notebook" and "note-to-source" as graph edges. The database automatically handles vector embeddings for semantic search across all content types.

### Async Repository Pattern

The [`open_notebook/database/repository.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/database/repository.py) module implements `db_connection` and `repo_query` helpers that wrap the async SurrealDB driver. These utilities manage connection pooling and query execution, ensuring that FastAPI endpoints can fire multiple concurrent database queries without blocking the event loop. The repository pattern abstracts SurrealQL syntax from the business logic layer.

### Automatic Schema Migrations

On API startup, the `AsyncMigrationManager` class in [`open_notebook/database/async_migrate.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/database/async_migrate.py) applies pending schema changes automatically. This ensures that the database structure remains synchronized with the application code across deployments, handling new tables, indexes, and relationship definitions without manual intervention.

## Inter-Tier Communication Flow

The three tiers communicate through well-defined interfaces that enforce separation of concerns. The frontend calls REST endpoints exposed by FastAPI, which processes requests through LangGraph workflows before persisting data via async SurrealDB connections.

1. **Frontend to API**: TanStack Query sends HTTP requests to `http://localhost:5055` with CORS headers configured in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) via the `_cors_headers` implementation.

2. **API to Database**: Endpoints invoke `repo_query()` from [`open_notebook/database/repository.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/database/repository.py) to execute SurrealQL statements asynchronously.

3. **API to AI Providers**: The [`open_notebook/ai/model_manager.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/ai/model_manager.py) uses Esperanto to route requests to appropriate LLM providers based on configuration and context window requirements.

4. **API to Frontend**: JSON responses flow back to TanStack Query, which automatically caches results and updates Zustand stores to re-render React components.

## Code Implementation Examples

These practical examples demonstrate the interaction patterns between tiers.

Fetching notebooks from the frontend:

```typescript
// src/lib/api/notebooks.ts
import { useQuery } from '@tanstack/react-query';
import { apiClient } from './client';

export const useNotebooks = () => {
  return useQuery(['notebooks'], async () => {
    const { data } = await apiClient.get('/api/notebooks');
    return data;
  });
};

```

Creating a notebook via FastAPI:

```python

# api/routers/notebooks.py

from fastapi import APIRouter, HTTPException
from open_notebook.database.repository import repo_query

router = APIRouter()

@router.post("/api/notebooks")
async def create_notebook(name: str):
    sql = "CREATE notebook CONTENT {name: $name}"
    try:
        result = await repo_query(sql, {"name": name})
        return result
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

```

Executing a LangGraph workflow:

```python

# open_notebook/graphs/ask.py usage pattern

from open_notebook.graphs.ask import ask_graph

async def answer_question(question: str, notebook_id: str):
    state = await ask_graph.ainvoke(
        {"question": question, "notebook_id": notebook_id},
        config={"run_name": "ask"}
    )
    return state["answer"]

```

## Summary

- Open Notebook separates concerns across three tiers: Next.js for presentation, FastAPI for application logic, and SurrealDB for data persistence.
- The frontend uses TanStack Query and Zustand for state management, communicating via REST to port 5055.
- FastAPI implements async-first design patterns with LangGraph workflows and Esperanto-based AI orchestration.
- SurrealDB handles graph relationships and vector search through async repository patterns with automatic schema migrations.
- All inter-tier communication uses async I/O to prevent blocking and enable high concurrency.

## Frequently Asked Questions

### How does the frontend communicate with the FastAPI backend?

The Next.js frontend uses TanStack Query to send HTTP requests to FastAPI endpoints running on port 5055. The `apiClient` instance configures the base URL through environment variables, while CORS middleware in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) handles cross-origin requests by mirroring allowed origins in the response headers.

### Why does Open Notebook use SurrealDB instead of PostgreSQL or MongoDB?

SurrealDB provides native graph database capabilities and built-in vector search in a single system, eliminating the need for separate vector databases like Pinecone or Milvus. According to the source code in [`open_notebook/database/repository.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/database/repository.py), this allows storing relationships like "source-to-notebook" alongside semantic embeddings for AI-powered search without complex polyglot persistence architectures.

### How does the backend handle multiple AI providers simultaneously?

The application tier uses the **Esperanto** library through [`open_notebook/ai/model_manager.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/ai/model_manager.py) to abstract provider-specific implementations. This enables routing requests to OpenAI, Anthropic, or Ollama based on configuration, context window requirements, and credential availability without changing the workflow logic in LangGraph graphs.

### What prevents database queries from blocking API requests?

All SurrealDB interactions use async/await patterns implemented in [`open_notebook/database/repository.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/database/repository.py). The `repo_query` function and `db_connection` helper leverage the async SurrealDB driver, allowing FastAPI to handle other incoming requests while waiting for database I/O to complete, maximizing throughput under concurrent load.