DEV Community

puffball1567
puffball1567

Posted on

Hello, RocheDB! A Nim Database Built Around Data Locality

Hello! I am building RocheDB, an open-source NoSQL document and vector store written in Nim.

The project starts with a simple question:

What if a database could avoid opening unrelated data before expensive
retrieval and application processing begin?

Modern systems accumulate documents, tenant data, application state, embeddings, logs, and knowledge bases. A request can spend significant resources on data that is not ultimately useful: reading it, transferring it, holding it in memory, reranking it, summarizing it, or passing it into an LLM context.

RocheDB is my attempt to make an application's natural data locality part of the storage and retrieval model.

The central idea: a ring

RocheDB uses a ring as a semantic and structural placement unit.

An application or import rule chooses a ring when writing data. That same ring can then define the initial scope of a read.

docs/japan/support
tenant/acme/orders/2026
users/123/profile
Enter fullscreen mode Exit fullscreen mode

These are not merely directory-like names. They are coordinates in the retrieval space. Records placed in the same ring are expected to be useful neighbors for retrieval.

That makes a ring different from an ordinary collection label. It says both:

  • where a record belongs; and
  • which local region should be opened first for a request.

A ring is not a B+ tree

RocheDB rings are not intended to replace B+ trees.

A B+ tree organizes data by ordered keys. It is excellent for primary-key reads, secondary-index lookups, time ranges, sorted pagination, and other queries that can be expressed as a key lookup or key range scan.

A B+ tree answers:

Where is this key or key range?

A RocheDB ring answers:

Which local region of the data should be opened first in this context?

They optimize different parts of a system. A B+ tree makes ordered key access efficient. A ring tries to reduce the semantic candidate set before more expensive downstream work begins.

Why orbital mechanics?

The naming and part of the model are inspired by orbital mechanics.

In an orbital system, a body's position can be estimated from compact orbital elements such as period, phase or epoch, eccentricity, and semi-major axis.

RocheDB uses that as an engineering abstraction.

A ring is like a semantic data orbit. Records in a ring inherit lightweight orbital metadata, including values such as a period and headAngle. This lets a ring act as both a placement unit and a small part of the query plan.

The celestial-mechanics vocabulary—rings, orbits, encounters, and
accretion—is not the value proposition. RocheDB is not a physics simulator.

The useful idea is that placement, movement, proximity, and retrieval scope can be explicit and observable, rather than hidden behind a central directory or reconstructed for every request.


The short version: RocheDB uses application-level locality to reduce the candidate set before expensive retrieval, reranking, memory use, network transfer, or LLM context construction begins.

A small example

Here is what ring placement looks like from Nim:

import rochedb

var db = rochedb.open(dataDir = "data")

db.setRingDescription(
  "docs/japan",
  "Japanese product documentation and support articles"
)

discard db.put(
  """{"slug":"refund","title":"Refund guide"}""",
  ring = "docs/japan"
)

discard db.put(
  """{"slug":"setup","title":"Setup guide"}""",
  ring = "docs/japan"
)
Enter fullscreen mode Exit fullscreen mode

If the application already knows that it needs Japanese documentation, it can
start with that ring:

for item in db.listByRing("docs/japan"):
  echo item.payload
Enter fullscreen mode Exit fullscreen mode

The same idea applies to vector retrieval:

let query = @[1.0'f32, 0.0'f32]

let hits = db.retrieve(
  query,
  ring = "docs/japan",
  budget = 3
)

for hit in hits:
  echo hit.payload
Enter fullscreen mode Exit fullscreen mode

The important detail is that docs/japan is not a label added after the retrieval. It is a placement decision at write time and an initial scope for reads.

Applications are still responsible for designing useful rings. But many already know meaningful locality: tenant, region, product area, document domain, user, or time range. RocheDB is an attempt to let the database use that information directly.

Why this matters for AI, RAG, and web systems

For transactional workloads, an efficient indexed lookup is often enough.

For retrieval-heavy workloads, finding one row is not always the expensive part. The larger cost can be dealing with a wide set of semantically weak candidates after the lookup.

This is particularly relevant to AI and RAG systems. A database may efficiently retrieve a key range, but the result can still contain many weak candidates.

Those candidates may then be embedded, reranked, summarized, kept in memory, or sent to an LLM.

RocheDB tries to reduce that candidate set earlier.

When ring placement reflects useful locality, the expected benefits are:

  • fewer records to rank;
  • fewer payloads held in memory;
  • fewer bytes transferred between services;
  • fewer tokens passed to downstream LLMs;
  • clearer boundaries for tenants, regions, backups, migrations, and authorization.

What the early numbers show

The current benchmarks do not claim that RocheDB is universally faster than every B+ tree-based database.

They test a narrower hypothesis: when ring placement captures useful locality, can RocheDB reduce the working set and downstream candidate volume while keeping the read path lightweight?


Working-set benchmark

With 100 rings and 10,000 documents, the number of records scanned per query decreased from 10,000 to 100: a 99% reduction in the candidate working set.


Memory-pressure benchmark

With 100 rings, 100,000 documents, and 512-byte payloads, candidate memory per query decreased from 93.079 MiB to 0.931 MiB: also a 99% reduction.


RAG-oriented cases

In a fixed-quality synthetic RAG case, records scanned decreased from 8,000 to 1,000 and tokens per query from 3960 to 657.8.

In a 400-document, 6-ring AI/RAG case study, records scanned decreased from 400 to 40, while tokens per query decreased from 615.2 to 231.6 with recall remaining 1.000.

These are early, reproducible results rather than universal performance claims.

They depend on ring placement expressing useful locality. The benchmark scripts,

their conditions, and their limitations are in the project repository.

Source code, documentation, benchmark scripts, and issue tracking are available at github.com/puffball1567/rochedb.

A longer-term hope

The immediate goal is practical: reduce unnecessary candidate data before expensive downstream processing.

If that can also contribute over time to lower token consumption in AI and RAG systems, less energy spent on unnecessary reads and computation, and less pressure to continually expand memory, storage, and compute hardware capacity, that would be a meaningful result.

RocheDB alone will not directly solve token, energy, or semiconductor demand.

But avoiding unnecessary data movement seems like a useful place to start.

Current boundaries

RocheDB is not a replacement for every database or every B+ tree use case.

It is most interesting when an application already has meaningful locality:
tenants, users, regions, topics, document groups, time partitions,
prompt/context stores, or RAG document collections.

It is currently a technical preview. I am not presenting it as a production replacement for PostgreSQL, Redis, MongoDB, or dedicated vector databases.

RocheDB provides a Nim API, CLI, server mode, C ABI, and language drivers. In this series, I plan to write about ring placement, retrieval, cluster behavior, benchmarks, Nim implementation details, and driver development.

I hope RocheDB can be useful both as a practical experiment in reducing unnecessary data movement and as a way to explore what a locality-first database model can look like.

Feedback, questions, and use cases are very welcome.

Top comments (1)

Collapse
 
mads_hansen_27b33ebfee4c9 profile image
Mads Hansen

The data-locality angle is worth more attention than it usually gets.

A lot of database performance discussions jump straight to indexes, caches, or query syntax. Those matter, but layout often decides whether the system is working with the hardware or asking it to fight back.

A few questions I’d be curious about for RocheDB:

  • how records are grouped on disk
  • whether locality is optimized for point reads, range scans, or graph-like traversal
  • how compaction affects locality over time
  • what happens when write patterns are less predictable
  • how secondary access paths avoid fighting the primary layout
  • whether locality hints are exposed to users or kept internal

The hard part is usually preserving locality after the first clean benchmark. Real workloads mutate, delete, backfill, and query from odd angles.

Cool direction. Small engines that make a strong bet on layout can teach bigger systems a lot.