Documentation

fenecdb is an embedded document database small enough to run inside a browser tab. It also keeps an app's file on a phone and serves any language over HTTP, a file per tenant; search is built in.

Try it now. The Playground runs the engine in this tab -- nothing to install. To put it to work, the Quickstart starts the server and runs a first query in a few commands.

What it is

Your documents live in one file, indexed as you declare, and you query them with one language, FenecQL — in the page, in an app, from Rust, or over HTTP from a server. A screen's live query runs again when a write changes what it reads, a replica on the device syncs with the server, and the server takes many clients' writes into the one file through one writer, their disk syncs shared, and many tenants into a file each.

create collection articles (
  title     text  @text,
  tags      [text],
  year      int   @hash,
  published timestamp @sorted
)

get articles select title
  where year >= 2024 and tags has "rust"
  order published desc
  limit 10

get articles select title, highlight(title)
  match title $1 fuzzy
  limit 10
One file, and search built in

fenecdb keeps its documents in one file and indexes them — hash, unique, ordered, text, points and vectors. The indexes are held in memory and built from the documents, the first time a query reads each, and a vector graph is saved in the file too, so an open need not build it again. It answers queries from inside a browser tab, in an app, or from a server any language reaches over HTTP.

Everything in these docs describes the engine as it is built today. Where something costs you a capability, that cost is stated next to the feature rather than at the bottom of the page.

One file. Records are appended to immutable 8 MiB segments and the byte sequence on disk is the byte sequence in memory, so a read decodes directly over the arena. A HashMap<DocId, Loc> offset index is the only helper structure in the whole store.

Search is not bolted on. @text is an index and match a query clause, ranked by BM25, with fuzzy, highlight() and facet beside it; for search by meaning, vector<N> is a type, @hnsw an index and near a clause. The planner knows them all, so a filter and a search are planned together rather than stacked on each other.

Where to go next

Pick the route that matches what you are doing. The sidebar files pages by what they are instead, so a few sit under another heading there: FenecQL and From SQL are Reference, the place to start writing queries, and Build from source is Contribute. Every page is listed below the routes.

New here

  • Playground

    The real engine in this tab, with collections to browse and a FenecQL editor. Nothing to install.

  • Quickstart

    Start the server, write two rows, query and search them with curl and from your language, and see them in the studio.

  • Quickstart: in the browser

    The database in a page, with no server: a Vite project, one package and a script.

  • Install

    The install script, Homebrew, a .deb or .rpm, a tarball, the image, a package for your language, or a build from source.

  • Your language

    Python, JavaScript, Go, Rust, .NET, Java, PHP, Ruby, Swift, Kotlin and Dart: one program in each, tested against a real server.

  • From SQL

    The SQL it reads as written, what it refuses and what to write instead, and where the meaning is not SQL's.

Build an app

  • FenecQL

    The language: a tour from the first write to a lookup and a total, then a reference page for each family of statements.

  • JavaScript and TypeScript

    The browser client, the query builder and generated TypeScript types.

  • Mobile and native apps

    Swift, Kotlin and Flutter: a file on the device, live queries driving the UI.

  • HTTP endpoint

    Start a server and send it FenecQL from curl or any language's standard library: raw statements, batches and writes that are safe to retry. The reference has every route, status and stream, and security and scoped access the tokens and policies.

  • Sync

    A local replica that reads without the network and writes optimistically.

  • Instead of Redis

    Counters, rate limits, locks, sessions, leaderboards and more, each a recipe a test runs.

  • Integrations

    LangChain, LlamaIndex, the Vercel AI SDK and React.

  • Agents and MCP

    fenecdb as an agent's search and memory tool over the Model Context Protocol.

  • Import

    A collection from SQLite or a live PostgreSQL table in one command.

  • Serverless and Cloudflare

    A database in a Durable Object, or a function talking to a server.

Run it in production

  • Server

    Running fenec-server: flags, tokens, durability, limits, containers.

  • Studio

    The admin pages the server can serve: collections, rows, a query editor and the server's numbers.

  • Replication

    Read replicas, promotion, archives and backups restored to a moment, every tenant of a node archived at once.

  • Tenants and sharding

    A file per tenant behind a router: two nodes and a router on one machine, a tenant, and a node lost and failed over. The guides, the reference and the design follow it.

  • Monitoring

    Metrics, dashboards, a slow-statement log, an audit log and traces.

  • Datadog and others

    Under Datadog, New Relic, Elastic and Grafana Cloud: the metrics check, the logs, a dashboard and traces.

The details

  • Limits

    What it does not do, and every hard-coded ceiling.

  • File format

    The layout of a file: its record kinds, their bodies, and why each exception exists.

  • How it works

    Segments, the mapped file, one writer, and why fenecdb has no buffer pool of its own; the four ways it ships and how the crates fit together.

  • Benchmarks

    YCSB against SQLite, PostgreSQL, MongoDB and Redis, writers beside readers, requests, text and vector search, and sizes, each family on a page with its method.

  • Compare

    Beside PostgreSQL, SQLite and PGlite: when to choose each.

  • Build from source

    Clone the repository, build with cargo and make, run the tests.

Every page

The sidebar's pages, grouped as it groups them.

Coding agents read the same pages as text: llms.txt is a brief with the rules FenecQL does not share with SQL, and llms-full.txt is every page in one file.

What it gave up

Staying small meant leaving some things out on purpose. The main ones:

  • One writer. Many readers, but one write or batch at a time.
  • No SQL dialect, and a join only on a key. Every client speaks FenecQL, over HTTP or in process; it reads SQL's everyday spellings as the statements they mean, a JOIN on an indexed key among them (From SQL).
  • No decimals. Store money as cents.
What it gave up, one by one

The list is short, and it is made of consequences of the design rather than a roadmap.

  • One writer, no MVCC. A write, or a /batch of them, holds the write lock for as long as it runs and lands whole or not at all; readers read beside it. There are no interactive transactions held open across requests.
  • A join only on a key. A query reads one collection, plus the children lookup attaches to each of its rows — and, chained, the children of those — and filters by another's rows only through an uncorrelated in (get …). SQL's JOIN on an indexed key reads as one of those, answered flat; a join of any other condition is none.
  • No SQL dialect. FenecQL is the one language, in the page, in Rust and over HTTP. It reads CREATE TABLE, INSERT … VALUES, UPDATE … SET, JOIN, IN (…), EXISTS, BETWEEN, LIKE and ON CONFLICT as the statements they mean and refuses the rest saying what to write; there is no wire protocol for SQL drivers, and no ORM speaks it.
  • No multi-writer replication, and no change of a field's type in place: it would rewrite every document under the write lock.
  • No decimal type. float is binary floating point and unfit for money; the answer is an int in cents.
  • Objects only in a json field. A typed field refuses one and a list holds one type; a json field holds any value JSON does, and a path reads into it.

The full accounting, including every hard-coded ceiling, is in Limits.

How it ships — the browser module, the shell, the server and the Rust library, with what each weighs — and how the crates fit together are on How it works.