Skip to content

HorizonDB

JSON key-value over WebSocket

HorizonDB

Memory above, PostgreSQL below.

The key-value server behind iHorizon. Reads and writes at memory speed, batched into PostgreSQL behind the scenes, spoken over one WebSocket from a zero-dependency Bun client.

Get started Protocol reference Benchmark results

What it is

HorizonDB is a JSON-oriented key-value database server written in Rust (edition 2024, async Tokio, unsafe forbidden). Clients talk to it over a WebSocket with small JSON packets. Every read and every write is served from an in-memory store; a background task writes the changed keys to PostgreSQL in batches every flush_interval_secs (300 s by default), and a graceful shutdown flushes everything first.

import { HorizonDB } from "horizondb";

const db = await HorizonDB.connect({ url: "ws://127.0.0.1:8080", username: "admin", password: "secret" });

await db.set("guild.42.settings.prefix", "!");                 // dot keys merge into one document
await db.add("guild.42.stats.messages");                       // → 1, the new value, no extra read
await db.push("guild.42.mods", "1234", { returnValue: true }); // → ["1234"]
await db.cache("cooldown.42.daily", true, 86_400_000);         // gone in 24 h

console.log(await db.get("guild.42"));
// { settings: { prefix: "!" }, stats: { messages: 1 }, mods: ["1234"] }

Why

A Discord bot hammers a handful of large JSON documents (a guild, a member, a counter) from many shards at once. A SQL round trip on every add or push makes that slow; a pure in-memory store forgets everything on restart. HorizonDB sits on the line between the two: the working set lives in memory, the durable copy lives in plain PostgreSQL tables you already know how to query, back up and restore.

Key features

  • Memory above


    Every operation is answered from memory. A push into a multi-megabyte document edits it in place under a per-key lock: documents are never deep-copied on the hot path.

  • The horizon


    Dirty keys are batch-flushed to PostgreSQL (UNNEST upserts, ANY deletes) every flush_interval_secs, and on SIGINT / SIGTERM.

  • PostgreSQL below


    One plain table per namespace: id VARCHAR(255) PRIMARY KEY, value TEXT. Keys load lazily on first access, single-flighted.

  • Bounded memory


    Idle documents are packed to compact JSON text (about 10x smaller), and clean idle documents leave memory entirely. RAM follows the working set, not everything read since startup.

  • No lost updates


    Read-modify-write operations are serialized per key. Sixteen workers on one counter end at the exact sum, checked on every benchmark run.

  • Nested keys


    user.profile.name addresses inside one document per base key, up to 32 levels deep. Reads copy only the sub-tree you asked for.

  • Answers, not acks


    add / sub return the new number, delete whether the key existed, push / pull the resulting array on request.

  • Hardened by default


    argon2id or constant-time auth, validated table names, bounded messages, per-connection backpressure, request deadlines, idle-link pings.

Where to next

  • Getting started

    Run a server and a PostgreSQL container with one script, then send your first request.

  • Configuration

    Every [server], [database] and [auth] option, its default and its validation rule.

  • Architecture

    Write-behind, dirty generations, flush batching, cold loads and the three memory tiers.

  • Protocol

    Packet shapes, every operation with request and response, errors and limits.

  • TypeScript SDK

    The Bun client: options, methods, error classes, reconnection.

  • Operations

    systemd and pm2, graceful shutdown, the stats lines, memory tuning, backups.

  • Benchmarks

    Method, reference numbers, memory measurements and the interactive results.

  • FAQ

    Restarts, cold starts, memory usage, closed connections and other surprises.

Project status

HorizonDB is part of the iHorizon project. It is a work in progress: the wire protocol may still change, so upgrade the server and the SDK together.

Landing page Brand kit Source code