# Concepts

How OrbSearch is shaped, from what a merchant sends to what a shopper gets back.

The write path: a shop's export becomes a snapshot and its release files a release, and an index run builds both into Meilisearch's indexes while the Query API loads the release. The read path: the Query API turns a shopper's query into one call to Meilisearch and assembles the answer with its trace.

OrbSearch has two paths. What a merchant sends is built ahead of time, into Meilisearch's indexes and the release the Query API holds, so a search only has to compute and ask the engine once.

## The write path

A merchant sends two things, and OrbSearch keeps each as a version that never changes:

- The [catalog](/docs/reference/glossary#catalog) is the export the shop already writes. Each upload is kept byte for byte as a [snapshot](/docs/reference/glossary#snapshot).
- The [release](/docs/reference/glossary#release) is the whole search configuration, one JSON file per area. Storing one changes nothing; [publishing](/docs/reference/glossary#publish) makes it the active one.

An [index run](/docs/reference/glossary#index-run) then takes one snapshot and one release live, doing only what the change needs. A new catalog is built into new indexes beside the live ones and swapped in, so shoppers never see half a catalog.

A run starts when a catalog arrives, when a release or an import is published, when a feed's export changed, when you ask for a rebuild, and when a sale window opens or closes.

## The read path

A search is computed from the request and the live release, then sent to Meilisearch as one call. The Query API [resolves](/docs/reference/glossary#resolution) the query in the shop's own words and applies the merchant's [rules](/docs/reference/glossary#rule), then plans the searches. After the engine answers, it ranks and assembles the answer.

Every step writes what it decided into the [trace](/docs/reference/glossary#trace), and every answer names the release and snapshot it came from:

```sh title="Terminal"
curl -s 'http://127.0.0.1:7800/v1/search?query=couch' | jq -c '{release, snapshot}'
```

```json title="Answer: 200 · 4.6 ms · release b25a6aaa"
{"release":"b25a6aaac6a46319b4ee3d25","snapshot":"753be49b9a9a503b3affac97"}
```

Two exceptions: a query that named something and found nothing is searched again, without parts of what it named, and a redirect to a fixed URL asks the engine nothing.

## The parts

- **Control plane:** the management API and the panel. It keeps releases and index runs in Postgres, and each snapshot's bytes in its storage.
- **Indexer:** runs the index runs, building a snapshot and a release into Meilisearch.
- **Query API:** answers searches, products and URLs without a key. A search never waits on a database.
- **Meilisearch:** holds the indexes, per entity type and locale.

## Why it is shaped this way

- **Fast without a cache.** What follows from the configuration is compiled when a release goes live, so a search is computation plus one engine call.
- **Every answer explains itself.** Releases and snapshots are named by their content and never change, so an answer's names say which configuration and catalog answered.
- **A rollback is a publish.** Publishing an earlier release takes it live again.
- **The engine holds nothing of its own.** Its indexes are built from a snapshot and a release, so a rebuild restores them.

## Next

- [Glossary](/docs/reference/glossary): every term, one sentence each.
- [Quickstart](/docs/quickstart): both paths on your machine in a few minutes.
- [Search](/docs/search): what a search request asks and what comes back.
