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:
frontend/src/pages/index.tsx— Main UI entry point using Zustand stores and TanStack Queryapi/main.py— FastAPI initialization and router registrationapi/routers/notebook.py— Notebook CRUD endpointsopen_notebook/graphs/*— LangGraph workflow definitionsopen_notebook/database/manager.py— Async SurrealDB connection and migration handleropen_notebook/ai/model_manager.py— Esperanto-based provider selectionCONFIGURATION.md— Environment variables for port configuration and database URLs
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →