Concepts
SemiLayer is an intelligence layer that sits between your application and your database. It reads your existing data, embeds it into vectors, and exposes semantic operations — search, similarity, feeds, and direct queries — through a typed client, REST, or WebSocket.
Your database stays where it is. SemiLayer never writes to it.
How it fits together
Search, similar, feed go through SemiLayer's vector index — your source is NOT hit at query time.
Query goes through the bridge — it reads directly from your source with
the where predicates you pass. Opt in with grants.query on the lens.
Analyze goes through the bridge for aggregation (or reduces in-process
when the bridge can't push down) and through the index for vector-narrowed
candidates. The result is tidy buckets ready for any chart library, with
drill-down rows replaying through the same RBAC + mapping pipeline query
uses. Opt in with grants.analyze.<name> on the lens.
Organization · Project · Environment
Three nested scopes:
- Organization — your company or team. Billing, members, and encryption keys live here.
- Project — a logical application within an org. Namespaces lenses and API keys. One project per product or per microservice is common.
- Environment — a deployment stage within a project. Default is
development. Production apps typically rundevelopment,staging, andproduction— each with its own sources, lenses, and API keys.
semilayer init stores your selection in .semilayerrc so subsequent CLI
commands know where to operate.
→ See Environments for the full model, promotion flow, and diff tooling.
Sources & Bridges
A Source is a connection to an existing data source — a database, an API, a file store. A Bridge is the adapter that knows how to read from a specific source type. Your config names the bridge; the service holds the credentials.
First-party bridge: @semilayer/bridge-postgres. Others (MySQL, MongoDB,
SQLite, and more) are available as separate packages; community bridges can be
built on the Bridge SDK.
→ See Connect a Source for every connection mode (managed, runner-local, airgap). → See Bridge SDK to build your own.
Lenses
A Lens is the core concept — a declaration of intelligence over a table. You define which fields to embed, which operations to expose, and who can access them.
Field types: text, number, boolean, date, json, enum, relation.
searchable is opt-in. Only fields with searchable: true (or
{ weight: N }) are embedded. Others are stored as metadata — returned in
results, filterable in query(), invisible to search().
Lens status moves through paused → indexing → ready → error.
→ See Schema (Config) for the full field/mapping/transform reference.
Operations
Operations are what a lens exposes. Each one is gated by a grant under
grants.<op> on the lens — declare the grant and the operation is live.
| Operation | Purpose | Docs |
|---|---|---|
search | Semantic search over embedded fields. Keyword or hybrid mode available per-call | Search |
similar | Nearest neighbors of an existing record by its stored vector | Search — Overview |
query | Structured read through the bridge — predicates, ordering, pagination | Query |
count | Sibling of query — scalar count for "how many rows match this predicate" | REST API → Count |
feed | Ranked, paginated, optionally live-updating streams. Declared under feeds.<name>, gated by grants.feed.<name> | Feeds |
analyze | Declarative dashboards — typed dim × measure aggregations, drillable to rows, optionally live. Declared under analyses.<name>, gated by grants.analyze.<name> | Analyze |
Search and similar share the same vectors — both are powered by the
top-level searchable flag on each FieldConfig, so there's no double-embed.
The Beam client
Beam is a typed client generated from your config. Run semilayer generate
to produce a semilayer/ folder with per-lens classes.
No codegen? @semilayer/client exposes the same methods on a BeamClient
class — you pass lens as a string argument.
→ See Beam Client for the full API.
API keys
API keys authenticate requests. Each environment mints its own set. The
environment slug is literal in the key prefix — no hardcoded dev/live.
| Prefix shape | Type | Use |
|---|---|---|
sk_<envSlug>_ | Secret | Backend, full access |
pk_<envSlug>_ | Public | Client-side, read-only, safe in frontend bundles |
ik_<envSlug>_ | Ingest | Webhook ingest only — cannot query |
rk_<orgSlug>_ | Runner | Self-hosted runner auth (org-scoped, not env-scoped) |
So an environment named production mints keys like sk_production_<random>;
an environment named staging mints sk_staging_<random>. The slug lets ops
see at a glance which environment a leaked key came from.
Per-user scoping layers on top: pass an end-user JWT in the X-User-Token
header (or via beam.withUser(token)) and the service enforces the lens's
grants against that user's identity — see
Auth & RBAC.
Ingest
Ingest is a background job coordinated through a durable job queue.
semilayer push --resume-ingestenqueues an ingest job.- The worker opens the bridge, reads the source in cursor-paged batches.
- Each batch is embedded, indexed, and written to the vector store.
- Lens status goes
paused → indexing → ready.
Full (push --rebuild) re-indexes from scratch. Incremental
(push --resume-ingest) resumes from the last cursor. For ongoing freshness,
combine with syncInterval (cheap incremental poll), smartSyncInterval
(scheduled full scan with tombstone detection), or webhook ingest
triggered by your own changefeed.
→ See Push & Ingest for sync options, the dead- letter queue, and manual re-indexing.
Ready to build? Head to the Quickstart to ship your first lens in under 5 minutes.