How Environment Variable Fallbacks Work for Database Credentials in Open Notebook

Open Notebook implements cascading fallback logic in open_notebook/database/repository.py that checks legacy variable names like SURREAL_PASS and constructs database URLs from address/port components when SURREAL_URL is unset.

Open Notebook connects to SurrealDB through environment variable configuration that prioritizes modern naming conventions while maintaining backward compatibility with legacy deployments. Understanding how these environment variable fallbacks for database credentials function helps operators migrate configurations without breaking existing connections. The fallback logic resides entirely within the Python repository layer, specifically in the database connection utilities that resolve credentials at runtime.

Fallback Logic for Database URL Construction

When SURREAL_URL is not present in the environment, Open Notebook automatically constructs the WebSocket connection string from component variables. In open_notebook/database/repository.py, the get_database_url() function implements this cascade:

  • Primary check: SURREAL_URL is read directly via os.environ.get()
  • Fallback construction: If unset, the code combines SURREAL_ADDRESS (defaulting to localhost) and SURREAL_PORT (defaulting to 8000) into the format ws://<address>/rpc:<port>

This ensures older deployments using split address/port configuration continue functioning without modification while new deployments can use the consolidated URL format.

Password Variable Aliasing

The codebase maintains compatibility with older password environment variable names through a priority lookup. The get_database_password() function in open_notebook/database/repository.py checks variables in this order:

  1. SURREAL_PASSWORD (modern naming)
  2. SURREAL_PASS (legacy naming)

The function returns the first non-empty value encountered, allowing gradual migration from legacy variable names without immediate breaking changes.

Required Variables Without Fallbacks

Certain connection parameters must be explicitly defined, as no fallback alternatives exist. These are read directly with os.environ.get() and passed to AsyncSurreal.use():

  • SURREAL_USER: Authentication username
  • SURREAL_NAMESPACE: SurrealDB namespace selection
  • SURREAL_DATABASE: Database name selection

These variables are mandatory for establishing a functional connection, and missing values will cause connection failures since no default values or legacy aliases are provided according to the implementation in open_notebook/database/repository.py.

Connection Flow Implementation

The db_connection context manager in open_notebook/database/repository.py orchestrates the credential resolution:

from open_notebook.database.repository import db_connection

async def health_check():
    async with db_connection() as db:
        # Simple query to verify the connection works

        await db.query("SELECT * FROM info::schema;")

Behind the scenes, the context manager:

  1. Creates an AsyncSurreal client using the resolved URL from get_database_url()
  2. Authenticates via signin with the username and password obtained through the fallback logic
  3. Selects the namespace and database using the use method

Configuration Examples

Modern Configuration (Preferred)

Set the complete connection string explicitly:

import os
os.environ.update({
    "SURREAL_URL": "ws://surrealdb:8000/rpc",
    "SURREAL_USER": "root",
    "SURREAL_PASSWORD": "my-secret",
    "SURREAL_NAMESPACE": "open_notebook",
    "SURREAL_DATABASE": "open_notebook",
})

Legacy Configuration

Using component variables and legacy password naming:

import os
os.environ.update({
    "SURREAL_ADDRESS": "surrealdb",   # No SURREAL_URL set

    "SURREAL_PORT": "8000",
    "SURREAL_USER": "root",
    "SURREAL_PASS": "my-secret",      # Legacy password name

    "SURREAL_NAMESPACE": "open_notebook",
    "SURREAL_DATABASE": "open_notebook",
})

In this scenario, get_database_url() returns "ws://surrealdb/rpc:8000" and get_database_password() returns "my-secret".

Summary

  • open_notebook/database/repository.py contains the get_database_url() and get_database_password() functions that implement fallback logic for legacy environment variables.
  • SURREAL_URL takes precedence, but if unset, the system constructs the URL from SURREAL_ADDRESS (default localhost) and SURREAL_PORT (default 8000).
  • SURREAL_PASSWORD is checked before falling back to the legacy SURREAL_PASS variable.
  • Required variables (SURREAL_USER, SURREAL_NAMESPACE, SURREAL_DATABASE) have no fallbacks and must be explicitly set.
  • The db_connection context manager handles the complete connection lifecycle using these resolved credentials.

Frequently Asked Questions

What happens if I set both SURREAL_URL and SURREAL_ADDRESS?

The get_database_url() function prioritizes SURREAL_URL and ignores SURREAL_ADDRESS entirely. Only when SURREAL_URL is undefined will the system fall back to constructing the URL from address and port components.

Is SURREAL_PASS still supported in new versions?

Yes. The get_database_password() function in open_notebook/database/repository.py checks SURREAL_PASS as a fallback when SURREAL_PASSWORD is unavailable. However, new deployments should use SURREAL_PASSWORD as documented in docs/5-CONFIGURATION/environment-reference.md.

Do I need to specify a port if using SURREAL_ADDRESS?

Only if you want a non-standard port. The fallback logic defaults SURREAL_PORT to 8000 when constructing the WebSocket URL from component parts. If using SURREAL_URL directly, you must include the port in the URL string if required.

Where is the source of truth for required environment variables?

While the fallback logic exists in code within open_notebook/database/repository.py, the canonical documentation in docs/5-CONFIGURATION/environment-reference.md lists SURREAL_URL, SURREAL_USER, SURREAL_PASSWORD, SURREAL_NAMESPACE, and SURREAL_DATABASE as the required variables for new deployments.

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 →