BitBarrel is a high-performance key/value database built in Nim, using the Bitcask storage model at the core. Bitcask is based on append-only updates on disk and keeping keys with file offsets in memory for fast one-seek reads. BitBarrel expands on this model in several aspects and can be used both as a library similar to Sqlite or as a traditional multithreaded network server using a binary websocket protocol.
BitBarrel offers fast writes, efficient reads, and robust crash recovery. It has a mix of key/value benefits (fast), range queries, batch operations, JSON document features like server side graph traversal, TTL support per key and last but not least - a builtin pubsub system including watchable keys. Given that it uses websockets it can also be used directly from frontends.
Some Features:
- Three index modes: hashβbased (O(1)), sorted CritBit trees (range queries), and twoβtier partitioned indexes for massive datasets
- Cursor-based pagination for efficient range queries and prefix searches without offset overhead
- Non-blocking background thread compaction β writes continue uninterrupted during background compaction
- WebSocket based client libraries for Nim, Go, Dart/Flutter, Python, TypeScript, C, and Zig
- JWT authentication with role-based access control (admin, readwrite, readonly) for secure network access
- Web Admin UI written in Flutter using the Dart client library
- Simple to use Docker container including Web Admin UI
import bitbarrel
# Open a database with default settings
var db = openBarrel("myapp.db")
# Store some data
discard db.set("user:42:name", "Alice")
discard db.set("user:42:email", "alice@example.com")
# Retrieve it
echo "User name: ", db.get("user:42:name")
# Clean up
db.close()Installation: nimble install β’ Build: nimble build β’ Tests: nimble test
package main
import (
"fmt"
"github.com/tankfeed/bitbarrel-go"
)
func main() {
client := bitbarrel.NewClient("localhost", 9876)
client.Connect()
defer client.Close()
// Create barrel with CritBit mode for ordered keys
client.CreateBarrel("metrics", "critbit")
client.UseBarrel("metrics")
// Store time-series data
for i := 0; i < 1000; i++ {
key := fmt.Sprintf("sensor:temp:%04d", i)
value := fmt.Sprintf("%.1f", 20.0 + float64(i%20)*0.5)
client.Set(key, value)
}
// Cursor-based pagination through range
var allItems []bitbarrel.KeyValue
cursor := ""
for {
items, nextCursor, hasMore, err := client.PrefixQuery("sensor:temp:", 100, cursor)
if err != nil {
panic(err)
}
allItems = append(allItems, items...)
if !hasMore {
break
}
cursor = nextCursor
}
fmt.Printf("Processed %d temperature readings\n", len(allItems))
}from bitbarrel import BitBarrelClient
# Connect to server with context manager
with BitBarrelClient("localhost", 9876) as client:
client.use_barrel("chat")
# Subscribe to user notification patterns
client.subscribe("user:*:notifications")
# Set up message handler
def on_message(event):
print(f"π¨ {event.topic}: {event.payload}")
client.on_message = on_message
# Start receiving messages in background
client.start_event_receiver()
# Publish messages to matching topics
client.publish("user:alice:notifications", "Welcome to the platform!")
client.publish("user:bob:notifications", "You have a new message")
# Keep connection open briefly to receive messages
import time
time.sleep(0.1)import { BitBarrelClient } from '@bitbarrel/client';
async function socialGraph() {
const client = new BitBarrelClient({
host: 'localhost',
port: 9876,
autoConnect: true
});
await client.createBarrel('social');
await client.useBarrel('social');
// Store users with friend relationships using _refs field
const aliceData = {
name: 'Alice',
age: 30,
_refs: {
friends: ['user:bob', 'user:charlie'],
posts: ['post:123', 'post:456']
}
};
const bobData = {
name: 'Bob',
age: 28,
_refs: {
friends: ['user:alice'],
posts: ['post:789']
}
};
await client.set('user:alice', JSON.stringify(aliceData));
await client.set('user:bob', JSON.stringify(bobData));
// Traverse friend relationships
const aliceFriends = await client.traversePath('user:alice', 'friends');
console.log(`Alice has ${aliceFriends.length} friends:`);
aliceFriends.forEach((friend: string) => {
console.log(` - ${friend}`);
});
// Find all connections (two-level traversal)
const allConnections = await client.traverse('user:alice', 'friends/*/friends', {
includeFullData: false,
extractArrays: true
});
console.log(`Found ${allConnections.length} total connections in graph`);
await client.close();
}
socialGraph().catch(console.error);import bitbarrel
import bitbarrel_client
# Local barrel with TTL support
var localDb = openBarrel("cache.db")
defer: localDb.close()
# Set keys with automatic expiration
discard localDb.set("session:abc123", "user_data", ttl=300) # 5 minutes
discard localDb.set("temp:calculation", "result", ttl=60) # 1 minute
# Network client for batch operations
var client = newClient("localhost", 9876.Port)
client.connect()
defer: client.close()
discard client.useBarrel("inventory")
# Batch set multiple items efficiently
let products = @[
("product:1:name", "Laptop"),
("product:1:price", "999.99"),
("product:2:name", "Phone"),
("product:2:price", "699.99"),
("product:3:name", "Tablet"),
("product:3:price", "499.99")
]
let successCount = client.setMany(products)
echo "Successfully stored ", successCount, " products"
# Use iterator for memory-efficient traversal of large datasets
echo "All products:"
var productIter = client.newPrefixIterator("product:", pageSize=100)
for (key, value) in productIter.items():
echo " ", key, " = ", value
# Cursor-based pagination example (manual control)
var cursor = ""
var allPrices: seq[float]
while true:
let (items, nextCursor, hasMore) = client.prefixQuery("product:", 50, cursor)
for (key, value) in items:
if key.endsWith(":price"):
allPrices.add(parseFloat(value))
if not hasMore:
break
cursor = nextCursor
echo "Average price: ", allPrices.sum() / allPrices.len.floatBitBarrel provides client libraries in multiple languages for remote access via WebSocket, with JWT authentication support:
| Language | Status | Auth | Batch | TTL | Watch | Notes |
|---|---|---|---|---|---|---|
| Nim | β Complete | β | β | β | β | Native implementation |
| Go | β Complete | β | β | β | β | Native implementation |
| Python | β Complete | β | β | β | β | Context manager support |
| Dart/Flutter | β Complete | β | β | β | β | Mobile + Web compatible |
| TypeScript | β Complete | β | β | β | β | Node.js + browser |
| C | β Complete | β | β | β | Binary protocol client | |
| Zig | β Complete | β | β | β | Direct WebSocket using libwebsockets |
All clients are 100% feature-complete as of 2026-01-21 β’ See individual client READMEs for detailed documentation.
| Metric | Value | Context |
|---|---|---|
| Write throughput (none sync) | ~188K ops/sec | Buffered, sequential writes |
| Write throughput (sync) | ~186K ops/sec | OSβlevel durability |
| Write throughput (fsync) | ~9.1K ops/sec | Diskβlevel durability |
| Read throughput | ~172K ops/sec | Random access via inβmemory index |
| Mixed workload (80% read) | ~137K ops/sec | Combined operations |
| Recovery speed | 40K+ keys/sec | With v2 hint files and incremental recovery |
See Performance Guide for detailed measurements.
docker run -d --name bitbarrel -p 8080:8080 -v bitbarrel-data:/data ghcr.io/gokr/bitbarrel:latestAccess: Server at ws://localhost:8080, Web Admin at http://localhost:8080/admin/ β’ Full Docker Guide
- Quick Setup - Installation and first steps
- Tutorial - Comprehensive guide with examples
- Examples Directory - Runnable example programs
- Features Overview - Barrel modes, compression, networking, and more
- Pub/Sub Messaging - Real-time messaging guide
- Network Guide - Client/server setup with JWT auth
- Configuration Guide - Tuning for your use case
- Performance Guide - Benchmarking and optimization
- Testing Guide - Test suite documentation
- Architecture - System design
- Roadmap - Future enhancements and priorities
MIT License