Quickstart

July 21, 2026 ยท View on GitHub

Zero to a running MongrelDB Tcl program in ten minutes. This guide walks through importing the package, starting the daemon, and writing, running, and understanding a complete script.


1. Prerequisites

You need Tcl 8.6+ and a mongreldb-server daemon.

Install Tcl

On Debian/Ubuntu:

sudo apt install tcl tcl-dev

On macOS:

brew install tcl-tk

Verify:

tclsh <<< 'puts [info patchlevel]'   # >= 8.6

Install mongreldb-server

Fetch a prebuilt server binary from the MongrelDB releases:

mkdir -p bin
curl -fsSL -o bin/mongreldb-server \
  https://github.com/visorcraft/MongrelDB/releases/download/v0.63.1/mongreldb-server-linux-x64
chmod +x bin/mongreldb-server

2. Start the daemon

By default mongreldb-server listens on http://127.0.0.1:8453 and stores data in the directory you pass as its first argument.

mkdir -p /tmp/mdb-data
/path/to/mongreldb-server /tmp/mdb-data

In another terminal, sanity-check it:

curl http://127.0.0.1:8453/health
# ok

3. Import the package

lappend auto_path /path/to/MongrelDB-Tcl/src
package require mongreldb
set db [mongreldb::connect http://127.0.0.1:8453]

4. Write your first script

Create demo.tcl:

lappend auto_path src
package require mongreldb

# 1. Connect to the daemon.
set db [mongreldb::connect http://127.0.0.1:8453]

# 2. Health check before doing anything else.
if {![mongreldb::health $db]} {
    puts stderr "daemon not reachable"
    exit 1
}

# 3. Create a table. Two optional fields extend the schema:
#    - enum_variants: a fixed set of allowed values for a text column.
#    - default_value: a string applied when a row omits the column.
set cols [list \
    [dict create id 1 name id       ty int64   primary_key 1 nullable 0] \
    [dict create id 2 name customer ty varchar primary_key 0 nullable 0] \
    [dict create id 3 name amount   ty float64 primary_key 0 nullable 0 default_value 0.0] \
    [dict create id 4 name status   ty varchar primary_key 0 nullable 0 \
               enum_variants [list active inactive paused] default_value active] \
]
mongreldb::createTable $db orders $cols

# 4. Insert rows. cells is an even-length list {colId value ...}.
mongreldb::put $db orders {1 1 2 Alice 3 99.5 4 active}
mongreldb::put $db orders {1 2 2 Bob   3 150.0 4 inactive}

# 5. Query with a native index condition. Projection selects column ids 1,2.
set cond [mongreldb::condition range [dict create column_id 3 lo 100.0]]
set res [mongreldb::query $db orders [list $cond] {1 2} 100]
puts "rows: [llength [dict get $res rows]]"

# 6. Count the rows.
puts "total rows: [mongreldb::count $db orders]"

Run it:

tclsh demo.tcl

You should see the row count of 2.

5. What each part does

CodeWhat it does
mongreldb::connectBuilds a client targeting one daemon.
mongreldb::healthGET /health; returns 1 when the daemon answers.
mongreldb::createTablePOST /kit/create_table. Column ids are the on-wire identifiers.
enum_variantsOptional. Constrains a text column to a fixed value set; server-enforced on commit. Omit = absent.
default_valueOptional string default. Literal "now"/"uuid" strings go here; use default_expr only for dynamic defaults. Omit = absent.
default_value_jsonOptional raw null, boolean, or number default, emitted as default_value. Caller must match the column type.
default_exprOptional dynamic now or uuid default.
mongreldb::putSingle-op transaction: POST /kit/txn with one put op. cells is flattened to [col_id, val, ...].
mongreldb::queryBuilds a /kit/query body. Conditions push down to native indexes.
projection {1 2}Server returns only those column ids, saving bandwidth.
limit 100Caps the result; check the truncated key afterward.
mongreldb::countGET /tables/{name}/count.

6. History retention and time travel

MongrelDB keeps a durable MVCC history window. You can inspect it, widen it, and query older epochs with AS OF EPOCH.

puts [mongreldb::historyRetentionEpochs $db]  ;# current window, e.g. 1024
puts [mongreldb::earliestRetainedEpoch $db]   ;# oldest readable epoch, e.g. 3

# Widen the window. The response contains the updated values.
set resp [mongreldb::setHistoryRetentionEpochs $db 1000]
puts [dict get $resp history_retention_epochs]  ;# 1000

# Read the table as it existed at a captured commit epoch.
mongreldb::put $db orders {1 1 2 99.5}
set insertEpoch [mongreldb::lastEpoch $db]
set rows [mongreldb::sql $db "SELECT id, amount FROM orders AS OF EPOCH $insertEpoch"]

Increasing retention cannot restore history that has already been pruned. The window is a durable GC/time-travel policy, so it requires admin privileges when the daemon is running with auth.

7. Common pitfalls

Using the column name instead of the column id. Every on-wire API uses the numeric id from createTable, never the name. Conditions take the numeric column_id, not the string name.

Treating a single put as non-transactional. put is a one-op transaction. A unique constraint violation surfaces as a conflict error (HTTP 409), not as a silent no-op.

Expecting mongreldb::sql to always return rows. The /sql endpoint streams Arrow IPC for SELECT in most builds, so sql returns the decoded JSON when the server honors format:json, or {} for non-JSON bodies.

Pointing at a daemon that requires auth. If the daemon was started with --auth-token or --auth-users, every call fails with an auth error unless you use connectWithToken or connectWithBasicAuth. See auth.md.

Next steps

  • transactions.md - atomic batches, idempotency, retries
  • queries.md - every native index condition
  • sql.md - recursive CTEs, window functions, CREATE TABLE AS SELECT
  • auth.md - bearer tokens, basic auth, user/role management
  • errors.md - the full error category set and recovery patterns