How Open Notebook's Three-Tier Architecture Works: Frontend, API, and Database

Open Notebook implements a three-tier architecture that separates a React/Next.js frontend (port 3000), a FastAPI backend (port 5055), and a SurrealDB database (port 8000), with tiers communicating via HTTP REST and SurrealQL protocols.

The lfnovo/open-notebook repository is an open-source knowledge management system built for local-first, AI-powered note-taking. Its modular three-tier architecture ensures clean separation between user interface, business logic, and data persistence, enabling private deployment without external API dependencies for data storage.

Frontend Tier: React and Next.js

The presentation layer runs on port 3000 and is built with Next.js and React. According to the root [CLAUDE.md](https://github.com/lfnovo/open-notebook/blob/main/CLAUDE.md), the frontend provides the notebook interface, source-upload widgets, chat interfaces, semantic search, and podcast generation controls.

State management relies on Zustand, while data fetching uses TanStack Query to communicate with the FastAPI backend. The UI component library consists of shadcn/ui styled with Tailwind CSS. All user actions trigger HTTP requests to the REST endpoints exposed by the API tier, ensuring the frontend remains strictly responsible for presentation and user interaction.

API Tier: FastAPI

The application layer operates on port 5055 using FastAPI as the web framework. This tier implements all business logic, orchestrates LangGraph workflows, and mediates every request between the frontend and database.

REST Endpoints and Business Logic

The API exposes REST endpoints for core entities including notebooks, sources, notes, and chat sessions. In api/main.py, the FastAPI application initializes with CORS configuration and registers routers such as api/routers/notebook.py, which handles CRUD operations for notebook resources.

LangGraph Workflow Orchestration

The API utilizes LangGraph state machines to manage complex workflows. The open_notebook/graphs/* directory contains graph definitions for:

  • Source ingestion and text extraction
  • Content transformation pipelines
  • Conversational chat with context retrieval
  • Podcast generation workflows

Model Management via Esperanto

LLM calls route through the Esperanto library via open_notebook/ai/model_manager.py. The ModelManager class abstracts provider-specific implementations, supporting OpenAI, Anthropic, Ollama, and other compatible endpoints through a unified interface.

Async Database Connectivity

All database operations use an async SurrealDB driver. The open_notebook/database/manager.py file implements the async wrapper that handles connection pooling, query execution, and automatic schema migrations at startup.

Database Tier: SurrealDB

The data persistence layer runs on port 8000 using SurrealDB. As documented in open_notebook/database/CLAUDE.md, SurrealDB stores the graph relationships between notebooks, sources, notes, and chat sessions.

SurrealDB's native vector support holds embeddings for semantic search, enabling fast Retrieval-Augmented Generation (RAG) queries without requiring a separate vector database. The API connects to SurrealDB asynchronously using the SurrealQL protocol, applying migrations automatically when the application initializes.

Inter-Tier Communication and Data Flow

The architecture follows a strict communication pattern:


[Browser] → HTTP (REST) → FastAPI → async SurrealQL → SurrealDB

When a user uploads a source file, the frontend POSTs to the API, which extracts text, generates embeddings via the configured AI provider, and stores the vectorized data in SurrealDB. For chat queries, the API retrieves relevant sources using vector similarity search, passes the context to the LLM through the ModelManager, and returns the generated response to the frontend.

Key Implementation Files

Understanding the three-tier architecture requires familiarity with these specific files:

Implementation Examples

Creating a Notebook via the API

import httpx

BASE = "http://localhost:5055"

async def create_notebook(name: str):
    async with httpx.AsyncClient() as client:
        resp = await client.post(
            f"{BASE}/notebooks",
            json={"title": name}
        )
        resp.raise_for_status()
        return resp.json()

Querying SurrealDB Directly

from surrealdb import Surreal

db = Surreal("ws://localhost:8000")
await db.signin({"user": "root", "pass": "root"})
await db.use("open_notebook", "my_namespace")

async def get_notes(notebook_id: str):
    query = f"SELECT * FROM note WHERE notebook = '{notebook_id}'"
    result = await db.query(query)
    return result[0]["result"]

Running a LangGraph Podcast Workflow

from open_notebook.graphs.podcast import podcast_graph

async def generate_podcast(source_id: str):
    state = {"source_id": source_id}
    result = await podcast_graph.ainvoke(state)
    return result["podcast_url"]

Summary

  • Open Notebook's three-tier architecture strictly separates the Next.js frontend (port 3000), FastAPI backend (port 5055), and SurrealDB database (port 8000).
  • The frontend uses Zustand for state and TanStack Query for API communication, while the backend orchestrates LangGraph workflows and manages LLM providers via Esperanto.
  • SurrealDB handles both relational graph data and vector embeddings, enabling semantic search without additional services.
  • All tiers communicate asynchronously, with the API layer translating HTTP REST requests into SurrealQL database operations.

Frequently Asked Questions

What ports does Open Notebook use for each tier?

The frontend runs on port 3000, the FastAPI backend listens on port 5055, and SurrealDB operates on port 8000. These defaults are configurable via environment variables defined in CONFIGURATION.md.

How does the API handle different LLM providers?

The open_notebook/ai/model_manager.py implements the Esperanto library abstraction, which routes LLM calls to multiple providers including OpenAI, Anthropic, and Ollama through a unified interface, allowing users to switch models without changing application code.

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

SurrealDB was selected for its native graph database capabilities and built-in vector storage, which eliminates the need for separate databases to handle document relationships and semantic search embeddings required for the RAG functionality.

How does data flow when I upload a document?

The frontend sends the file via HTTP POST to the FastAPI backend, which processes the content through LangGraph ingestion workflows, generates embeddings using the configured AI provider, and stores both the text and vectors in SurrealDB using async SurrealQL queries.

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 →