# How to Set Up a Local Development Environment with API and SurrealDB for Open Notebook

> Quickly set up a local development environment with FastAPI API and SurrealDB for Open Notebook using Docker Compose. Launch the web interface and REST API effortlessly.

- Repository: [Luis Novo/open-notebook](https://github.com/lfnovo/open-notebook)
- Tags: how-to-guide
- Published: 2026-06-24

---

**Docker Compose provides the fastest path to launch the Open Notebook FastAPI backend and SurrealDB together, exposing the web interface on port 8502 and the REST API on port 5055.**

Open Notebook is a FastAPI-based application that persists all data in SurrealDB. Setting up a local development environment requires orchestrating both services so the API can communicate with the database over WebSocket. This guide walks you through the Docker Compose approach and the optional source-based workflow using the actual implementation from the `lfnovo/open-notebook` repository.

## Configure Docker Compose for Local Development

The repository includes a pre-configured [`docker-compose.yml`](https://github.com/lfnovo/open-notebook/blob/main/docker-compose.yml) that defines both the SurrealDB and Open Notebook services. This configuration uses the official `surrealdb/surrealdb:v2` image for the database and `lfnovo/open_notebook:v1-latest` for the application.

Create a [`docker-compose.yml`](https://github.com/lfnovo/open-notebook/blob/main/docker-compose.yml) file with the following content:

```yaml
services:
  surrealdb:
    image: surrealdb/surrealdb:v2
    command: start --log info --user root --pass root rocksdb:/mydata/mydatabase.db
    user: root
    ports:
      - "8000:8000"
    volumes:
      - ./surreal_data:/mydata
    restart: always

  open_notebook:
    image: lfnovo/open_notebook:v1-latest
    ports:
      - "8502:8502"
      - "5055:5055"
    environment:
      - OPEN_NOTEBOOK_ENCRYPTION_KEY=change-me-to-a-secret-string
      - SURREAL_URL=ws://surrealdb:8000/rpc
      - SURREAL_USER=root
      - SURREAL_PASSWORD=root
      - SURREAL_NAMESPACE=open_notebook
      - SURREAL_DATABASE=open_notebook
    volumes:
      - ./notebook_data:/app/data
    depends_on:
      - surrealdb
    restart: always

```

## Set the Encryption Key

Before starting the stack, you must replace the placeholder encryption key in the [`docker-compose.yml`](https://github.com/lfnovo/open-notebook/blob/main/docker-compose.yml) file. The `OPEN_NOTEBOOK_ENCRYPTION_KEY` environment variable is used by [`open_notebook/utils/encryption.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/utils/encryption.py) to encrypt stored credentials like API keys.

Generate a secure random string and update the environment variable:

```bash

# Generate a random hex string

openssl rand -hex 16

# Or update the file directly

sed -i 's/change-me-to-a-secret-string/your-generated-key-here/' docker-compose.yml

```

## Launch the Development Stack

Start both services with Docker Compose. The `depends_on` directive ensures SurrealDB starts before the Open Notebook API.

```bash
docker compose up -d

```

Docker will pull the required images and create containers for both services. After approximately 15-20 seconds, the services will be ready:

- **SurrealDB**: Running on `ws://localhost:8000/rpc`
- **Open Notebook UI**: Available at http://localhost:8502
- **REST API**: Accessible at http://localhost:5055 with OpenAPI documentation at `/docs`

Verify the API health endpoint:

```bash
curl http://localhost:5055/health

# Expected response: {"status":"ok"}

```

## Verify the SurrealDB Connection

The Open Notebook API establishes the database connection during startup via [`open_notebook/database/async_migrate.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/database/async_migrate.py). This module creates an async SurrealDB client using the WebSocket URL and credentials defined in your environment variables.

To test the connection independently, use the SurrealDB Python client:

```python
import asyncio
from surrealdb import Surreal

async def test_connection():
    db = Surreal("ws://localhost:8000/rpc")
    await db.connect()
    await db.signin({"user": "root", "pass": "root"})
    await db.use("open_notebook", "open_notebook")
    result = await db.query("INFO FOR DATABASE")
    print(result)

asyncio.run(test_connection())

```

Once connected, open the UI at `localhost:8502`, navigate to **Models**, and add a provider configuration (such as an OpenAI API key). Click **Test** to confirm the API can write encrypted credentials to SurrealDB via the endpoints defined in [`api/routers/models.py`](https://github.com/lfnovo/open-notebook/blob/main/api/routers/models.py).

## Run from Source for Development

If you need to modify the FastAPI source code rather than use the pre-built image, run the stack from source:

1. Clone the repository and install dependencies:
   ```bash
   pip install -r requirements.txt
   ```

2. Start SurrealDB locally (using the same Docker image):
   ```bash
   docker run -d --name surrealdb -p 8000:8000 \
     surrealdb/surrealdb:v2 start --user root --pass root rocksdb:/mydata/db
   ```

3. Export the required environment variables:
   ```bash
   export OPEN_NOTEBOOK_ENCRYPTION_KEY="your-secret-key"
   export SURREAL_URL="ws://localhost:8000/rpc"
   export SURREAL_USER="root"
   export SURREAL_PASSWORD="root"
   export SURREAL_NAMESPACE="open_notebook"
   export SURREAL_DATABASE="open_notebook"
   ```

4. Launch the FastAPI server:
   ```bash
   uv run python run_api.py
   ```

The entry point [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) mounts all routers including `/sources`, `/notes`, and `/search`, and registers CORS middleware for the frontend.

## Key Source Files

Understanding these core files helps when debugging or extending the local environment:

- **[`docker-compose.yml`](https://github.com/lfnovo/open-notebook/blob/main/docker-compose.yml)**: Defines the multi-container setup with SurrealDB and Open Notebook services
- **[`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py)**: FastAPI entry point that initializes the application and registers all API routers
- **[`open_notebook/database/async_migrate.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/database/async_migrate.py)**: Creates the async SurrealDB client on startup and runs database migrations
- **[`open_notebook/utils/encryption.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/utils/encryption.py)**: Handles credential encryption using the `OPEN_NOTEBOOK_ENCRYPTION_KEY` environment variable
- **[`api/routers/models.py`](https://github.com/lfnovo/open-notebook/blob/main/api/routers/models.py)**: REST endpoints for managing AI provider configurations
- **[`run_api.py`](https://github.com/lfnovo/open-notebook/blob/main/run_api.py)**: Convenience script to launch the API directly for local development

## Summary

- **Docker Compose** is the recommended approach for setting up a local Open Notebook development environment with SurrealDB.
- The [`docker-compose.yml`](https://github.com/lfnovo/open-notebook/blob/main/docker-compose.yml) configures SurrealDB on port 8000 and maps the Open Notebook UI (8502) and API (5055).
- You must set a unique `OPEN_NOTEBOOK_ENCRYPTION_KEY` before starting the stack to ensure credential security.
- The API connects to SurrealDB via WebSocket using parameters defined in environment variables, initialized in [`async_migrate.py`](https://github.com/lfnovo/open-notebook/blob/main/async_migrate.py).
- For code modifications, run from source using [`run_api.py`](https://github.com/lfnovo/open-notebook/blob/main/run_api.py) after starting SurrealDB separately.

## Frequently Asked Questions

### How do I change the default SurrealDB credentials in local development?

Edit the `command` line in the [`docker-compose.yml`](https://github.com/lfnovo/open-notebook/blob/main/docker-compose.yml) surrealdb service to specify different `--user` and `--pass` values, then update the corresponding `SURREAL_USER` and `SURREAL_PASSWORD` environment variables in the open_notebook service. Restart the stack with `docker compose up -d` to apply changes.

### Why does the Open Notebook container fail to start with "Connection refused" errors?

This typically occurs when the Open Notebook API attempts to connect before SurrealDB is fully initialized. The `depends_on` directive in Docker Compose only controls startup order, not readiness. Wait 15-20 seconds after starting the stack, or configure a health check dependency in your compose file to ensure SurrealDB accepts connections before the API starts.

### Can I use a different database backend instead of SurrealDB?

No. According to the source code in [`open_notebook/database/async_migrate.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/database/async_migrate.py), the application is specifically designed to use SurrealDB's WebSocket protocol and query syntax. The `Surreal` client is hardcoded into the database abstraction layer, making SurrealDB a requirement for running Open Notebook.

### How do I persist data between container restarts?

The [`docker-compose.yml`](https://github.com/lfnovo/open-notebook/blob/main/docker-compose.yml) includes volume mappings that persist data to your host filesystem. SurrealDB stores data in `./surreal_data` mapped to `/mydata` inside the container, while Open Notebook uses `./notebook_data` mapped to `/app/data`. These directories survive Docker container restarts and recreations.