Self-hosted service
Restream/reindexer avatar
Restream/reindexer

Reindexer: an embeddable in-memory document database for complex queries

Embeddable, in-memory, document-oriented database with a high-level Query builder interface.

812 stars60 forksC++Apache-2.0

At a glance

What is it?
Reindexer is a C++ in-memory document database with a Go API, built by Restream as a faster alternative to Elasticsearch, with an ORM-like query builder and a SQL compatible interface. It is embeddable rather than a service you run, and it also ships as a server with an HTTP API and a Docker image.
Who is it for?
Reindexer suits a Go service that wants document search with joins and aggregations inside its own process, without operating a search cluster, and that can accept an in-memory dataset. It is the wrong choice for a workload whose data does not fit in memory, for a team that needs the operational surface of a mature search cluster with rolling upgrades and distributed replicas, and for a project whose only requirement is a full text index on one field.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Reindexer is and who built it

Reindexer is described as an embeddable, in-memory, document-oriented database with a high-level Query builder interface, and the goal is stated plainly: to provide fast search with complex queries.

The origin story is in the README too. The team at Restream were not happy with Elasticsearch and created Reindexer as a more performant alternative. That is a specific and useful framing, because it tells you the design target: an Elasticsearch-shaped problem, full text search over documents with structured fields, solved by embedding the engine in the application rather than running it as a service.

The split between the two languages is the other thing to understand. The core is written in C++ and the application level API is in Go, and this README documents the Go connector and its API. The server and HTTP API are described separately in the C++ documentation.

The repository layout confirms the shape. There are cpp_src/ for the core, bindings/ for the language bindings, a cjson/ directory for JSON handling, dsl/ for the query language, jsonschema/ for schema handling, events/ for the event subscription machinery, pprof/ for profiling, and samples/ with both cpp and go directories. There are also top level Go files for the pieces of the public API, query.go, tx.go, iterator.go, reflect.go, expression.go, bindings.go, prometheus.go and tracing.go, alongside documentation files for the individual subsystems such as fulltext.md, hybrid.md, float_vector.md, replication.md and sharding.md.

The homepage is reindexer.io, the licence is Apache-2.0, and the last push was on 2026-10-20 with the recent releases v5.17.0, v5.16.0 and v5.15.0 through the summer of 2026.

The query surface: builder, SQL and joins

The feature list is where the difference from a plain key value store shows. Sortable indices, aggregation queries, indices on array fields, complex primary keys, composite indices, join operations, full text search, an ORM-like query interface and SQL queries.

The query builder is the higher level path, and the SQL interface is the escape hatch, so a team can start with structured calls and drop to SQL for the query that the builder cannot express.

The joins are the substantial part, and the README's table of contents shows the depth: a join, a nested join, an anti-join, and a Joinable interface, plus update queries with inner joins and subqueries. An anti-join and a nested join in an embeddable engine are not common, and they are what allow a document model to answer the questions that normally push a team towards a relational database or a search cluster with a separate aggregation service.

There is also subquery support, described as nested queries, and the table of contents lists updates, deletes, truncates, transactions with batch mode, and a set of specific update operations such as updating a field with an object, removing a field via an update query, updating array elements by index, concatenating arrays and removing array elements by value.

The array handling is worth singling out. There is a whole section on searching in array fields, including a variant with matching indexes and a variant using grouping, with query execution examples. In a document model, a field holding a list of values has ambiguous semantics, and a database that resolves that ambiguity explicitly is a step above a general purpose store with arrays bolted on.

Full text, vector and hybrid search

Three of the topic tags are ann-search, knn-search and vector-search, and the README lists full text search, vector indexes for approximate nearest neighbour and KNN queries, and hybrid search as separate capabilities.

That combination is the modern shape of a search requirement. Full text search alone answers lexical queries, where a document matches because it contains the words. Vector search answers semantic queries, where a document matches because its embedding is close to the query embedding. Hybrid search is the combination, and it exists because the two fail differently: lexical search misses paraphrase, and vector search misses the rare exact term such as an error code or a person's name.

The repository carries dedicated documentation files for these, fulltext.md, hybrid.md and float_vector.md, and the ftfastconfig.go file at the top level suggests the full text index has its own configuration surface, which is the sign of a real inverted index rather than a simple scan.

The interface is a C++ core with bindings, so a vector index here is not a separate service you call over HTTP. It is a data structure in the same address space as your query, which is the whole argument for embedding the engine.

The one caveat is that the README's table of contents points to a Limitations and known issues section, and for a system with this many subsystems that section is where the practical boundary of the vector and hybrid implementations will be described.

Performance and memory, as the project reports them

The README gives numbers, and it gives them as the project's own figures rather than as a third party measurement.

Performance has been the top priority from the start, and the benchmarks are said to show Reindexer on par with a typical key value database. On a single CPU core, the README reports up to 500K queries per second for the simplest point lookup by id, up to 50K queries per second for a query combining a range condition, an equality condition and an IN list, and up to 20K queries per second for that query joined against a subitems collection.

The shape of those three numbers is the interesting part. A 25x drop from a point lookup to a filtered query, and a further 2.5x drop when a join is added, is the profile of an index working as expected. It also tells you which query to expect to be slow, and the answer is a join on a large collection.

On memory, the aim is to consume as little as possible, and the claim is that most queries are processed without any memory allocation at all. The README attributes this to optimizations on both the C++ and the Go level, and the document structure of the repository, with the Go side handling reflection over user structs, is consistent with that claim.

The benchmarking results and more detail are in a separate benchmarking repository, Restream/reindexer-benchmarks, which is the right place to look for the methodology rather than taking these three figures on trust.

Embedded mode, server mode and the two installation paths

Reindexer can be used in two ways, and the README's table of contents separates them into installation for server mode and installation for embedded mode.

In server mode there is an official Docker image, and the C++ documentation covers the server and its HTTP API. That mode is for when you want Reindexer to look like a search service on the network, which is how you would point an existing Elasticsearch-shaped client at it.

Embedded mode is the mode the Go connector is for, and the README lists four ways to get the library, which is a more detailed set than most Go libraries document. There is the go.mod route, the go.mod route with a replace directive, a vendoring route for applications without a go.mod, and a go.mod route with vendoring. The reason there are four is that the library contains a C++ core, so it has to be built with cgo, and how you wire a cgo dependency into a build depends on how your project is structured.

The go.mod in the repository shows the module path is github.com/restream/reindexer/v5 and that it needs Go 1.24.0 or newer. The dependencies are light and tell you what the library itself uses: goccy/go-json for JSON, golang/snappy for compression, hashicorp/golang-lru for caching, iancoleman/orderedmap, prometheus/client_golang for the metrics exporter, stretchr/testify for tests, OpenTelemetry for tracing, and yaml.v3.

The OpenTelemetry and Prometheus dependencies are worth noting, because they mean the observability story is not an afterthought. There is a prometheus.go and a tracing.go at the top level, and the README's table of contents has a whole section on logging, debug, profiling and tracing, including heap profiling, CPU profiling, slow action logging, debug queries and custom allocator support.

The features that decide whether it scales

Two subsystems determine whether Reindexer can move past a single process, and both have their own documentation file at the repository root.

replication.md and sharding.md sit next to fulltext.md and hybrid.md, which tells you the project treats them as peer subsystems rather than as afterthoughts. Replication and sharding are what turn an embedded library into something that can be deployed as a replicated cluster, and they are the features that decide whether a team can use this in production or only inside one service.

Two more subsystems in the table of contents are easy to overlook. Events subscription is a mechanism for reacting to changes rather than polling, which is what an application needs if it has to keep a cache in step with the database. And the object cache, with a DeepCopy interface, a section on getting shared objects from the cache marked USE WITH CAUTION, and a section on limiting the size of the object cache, is a performance feature with a sharp edge, since shared objects handed out from a cache can be mutated by the caller in ways the database does not expect.

There is also a TTL mechanism, an expire data from namespace by setting TTL section, and atomic on update functions. The TTL is what makes an in-memory store viable for session-like data, where a document should disappear on its own rather than by a delete statement.

The other feature worth naming is direct JSON operations, with upsert data in JSON format and get query results in JSON format. For a document database, being able to hand it a JSON document and get JSON back, without writing a struct and a reflection layer, is a substantial convenience for a service that already speaks JSON.

Where Reindexer is the wrong tool

The first limitation is the one in the name. It is an in-memory database, and the memory consumption section is about how little it uses, not about how much it can hold. A dataset that does not fit comfortably in the memory you are willing to give the process is a poor fit, and the README's own framing of the design goal, fast search with complex queries, is consistent with a working set assumption.

The second is the operational surface. The project exists because Restream wanted something better than Elasticsearch, and the case against Elasticsearch is usually made on latency and footprint. What Elasticsearch gives in return is a mature distributed model, a large ecosystem, and years of operational knowledge. An embedded library gives you none of that, because there is no server to operate, and also no cluster to grow into if the single process becomes a bottleneck.

The third is the language split. The core is C++, the application API is Go, and the README documents the Go connector while the server and HTTP API are documented elsewhere. A team that is not in Go and does not want a separate service has to look at the bindings, and the table of contents mentions Python and Java connectors plus third party connectors for PHP, Rust and .NET, but those are separate efforts with their own maintenance.

The fourth is the young major version. The module path ends in /v5, so the API has broken compatibility before and will probably do so again, and the README has a Limitations and known issues section plus a changelog.md, which are the places to look before depending on a particular call.

The fifth is the embedding requirement itself. A cgo dependency means your build needs a C++ toolchain, that cross-compilation becomes your problem, and that a static binary is no longer trivial.

How it compares with SQLite, Tantivy and an embedded Elasticsearch

SQLite is the comparison most readers will make first, and the difference in approach is the data model. SQLite is relational, with a fixed schema, and its query planner is among the best in the software world. Reindexer is document-oriented, so a record is a JSON-like object with nested structures and array fields, and the query is built over that. If your data is genuinely relational with stable relationships, SQLite will serve you better and with far less machinery.

Tantivy is the comparison for the search half. Tantivy is the Rust search library that powers tantivy-search and is a common building block for search systems, and it is a full text index rather than a document database. Reindexer uses the same kind of inverted index internally, and adds the document model, the joins, the aggregations and the vector indexes on top. Tantivy is a library to build a search system with; Reindexer is a database to embed.

The third comparison is with running Elasticsearch in embedded mode, which is not really supported, and so the practical alternative is running the real thing as a service. The trade there is the whole point of the project: you get the query capability without a cluster, an HTTP hop, an index refresh cycle and the operational overhead, and you give up the shard-level parallelism and the horizontal scale.

There is a fourth comparison that matters for anyone with mixed needs. Reindexer's hybrid search, with lexical and vector matching in one query, is the feature that decides between it and a separate vector database alongside a traditional search engine, because two systems mean two consistency models and two failure modes.

Licence, maintenance and how to evaluate it

The licence field on the repository records Apache-2.0, with the LICENSE file at the root. That is a permissive licence with an explicit patent grant, and for a project that grew out of a company's internal search requirement and is now published under Apache 2.0, it means an organisation can vendor it, modify it and ship it in a product without a copyleft obligation.

The project is not archived and the last push was on 2026-10-20, the same day as the writing of this page, so it is being actively worked on. The release cadence is visible in the version numbers, with v5.17.0 from 2026-09-26, v5.16.0 from 2026-08-19 and v5.15.0 from 2026-07-09, which is roughly monthly for a project of this scope. The CI badges show a GitHub Actions build and an AppVeyor build, and there is a changelog.md.

Three things to check before committing to it.

Read the limitations and known issues section, because for a system with vector search, hybrid ranking, joins and sharding, that section is where the honest limits are and it is the first thing a careful evaluator should read.

Look at replication.md and sharding.md, because those two documents decide whether the library can be used beyond a single process, and because a replication design for an in-memory store has to choose what happens to a node that fails, which is not the same question as in a disk-backed system.

Finally, run the benchmark repository against your own query shape. The three figures in the README describe a point lookup, a filtered query and a join, and they are the project's own numbers, so the real question is how your queries land against that profile, especially the join rate.

Editorial conclusion

Reindexer suits a Go service that wants document search with joins and aggregations inside its own process, without operating a search cluster, and that can accept an in-memory dataset. It is the wrong choice for a workload whose data does not fit in memory, for a team that needs the operational surface of a mature search cluster with rolling upgrades and distributed replicas, and for a project whose only requirement is a full text index on one field. Before adopting it, read the limitations and known issues section, and check the replication and sharding notes in the repository, since those two features are the ones that decide whether it can grow beyond a single process.

Frequently asked questions

What is Reindexer?

It is an embeddable, in-memory, document-oriented database with a high-level Query builder interface, with its core written in C++ and the application level API in Go. The team at Restream created it as a more performant alternative to Elasticsearch for fast search with complex queries.

What query features does Reindexer support?

Sortable indices, aggregation queries, indices on array fields, complex primary keys, composite indices, join operations including nested joins and anti-joins, subqueries, full text search, vector indexes, hybrid search, an ORM-like query interface and SQL queries, plus update, delete, truncate and transaction support.

How do I install Reindexer in a Go project?

The README lists four routes, because the library contains a C++ core and is consumed through cgo: using go.mod, using go.mod with a replace directive, vendoring for applications without a go.mod, and go.mod with vendoring. The module path is github.com/restream/reindexer/v5 and Go 1.24.0 or newer is required. There is also an official Docker image for server mode.

How fast is Reindexer according to the README?

The README reports that benchmarks show performance on par with a typical key value database, and on a single CPU core gives up to 500K queries per second for a lookup by id, up to 50K for a query combining a range, an equality and an IN list, and up to 20K for that query joined against a subitems collection. The benchmarking repository holds more detail.

Does Reindexer support vector and hybrid search?

Yes. The repository lists full text search, vector indexes for approximate nearest neighbour and KNN queries, and hybrid search as features, with dedicated documentation for the full text, hybrid and float vector components.

What licence is Reindexer released under?

Apache-2.0, with the terms in the LICENSE file at the root of the repository.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. README
  4. Releases
  5. Restream/reindexer on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/restream-reindexer.svg)](https://hysenlabs.com/projects/restream-reindexer)

Was this useful?