Schema (Config)
The sl.config.ts file is the single source of truth for your SemiLayer setup. It declares
your sources (which databases SemiLayer reads from), lenses (intelligent collections
over a table or collection), the relations between them, and your auth configuration.
The platform stores credentials, status, and indexes; your sl.config.ts declares
shape and is pushed up via semilayer push. Either side of that boundary can be edited
through the Console — but the config file is what your generated Beam client is built from.
Don't have a config file yet? The fastest way to bootstrap one is the Quick Connect wizard at console.semilayer.com → your org → Quick Connect. It connects a source, auto-detects fields, creates a lens, and exports the matching sl.config.ts — runnable as-is.
File location
SemiLayer searches for sl.config.ts (or sl.config.js) starting from the current working
directory and walking up to the filesystem root. Place it at the root of your project.
Top-level shape
Sources
A Source declares a database connection. The key ('main-db' below) is the source name
that lenses reference.
That's all sl.config.ts needs. Connection credentials live on the SemiLayer platform,
not in this file — they're either stored encrypted (managed mode) or held by your runner
(runner-local mode). See Connecting a source below.
Connecting a source — Console (recommended)
Open Console → Sources → Connect source. Pick your bridge, then choose a credentials location:
- Managed — paste the connection details. SemiLayer encrypts them at rest with AES-256-GCM and connects on your behalf (or via an assigned runner).
- Runner-local — no credentials stored. Set
SEMILAYER_SOURCE_<NAME>_<KEY>env vars on the runner instead —_URLfor URL-style bridges (Postgres, MySQL, MongoDB, Redis), or one var per config field (_HOST,_PORT,_DATABASE,_ACCESS_KEY_ID, …) for structured-config bridges. SemiLayer holds nothing. See Airgap mode.
After saving, the Console runs introspection and lists the available targets (tables / collections) so you can spot-check the connection.
Connecting a source — CLI
You'll be prompted for the connection URL (or the per-field config the bridge declares).
Pass --url "postgres://..." to skip the prompts in CI.
Multiple sources
Cross-source joins (a lens with a relation to another lens on a different source) are fully supported — the planner stitches results across bridges. Declare each source by name and reference both from the lens config:
Lenses
A Lens is the unit of intelligence over a table. The key becomes the lens name (and the property name on your generated Beam client).
Fields
Fields declare what to read from the source and how to expose it. The key becomes the output field name; the value declares its type, mapping, and any transforms.
Field types
| Type | TypeScript output | Use for |
|---|---|---|
text | string | Free-form strings, descriptions, titles |
number | number | Integers, floats, prices |
boolean | boolean | Flags, toggles |
date | string | ISO date / datetime strings |
json | unknown | Arbitrary JSON objects / arrays |
enum | string | One of a declared set of values |
relation | string | number | Foreign-key column referenced by a relations entry |
Primary key
You can declare the primary key in two equivalent ways:
If neither is specified, SemiLayer falls back to a column named id.
Marking fields for embedding
Add searchable: true to include a field in the semantic search embedding:
Higher-weighted fields are repeated in the embedding input, boosting their relevance signal in search results.
Column mapping (from)
When the source column name differs from your desired output field name:
When a field is built from multiple source columns, declare a merge strategy:
Transforms
Apply a transform chain to the resolved value before indexing:
Available transforms
| Transform | Parameters | What it does |
|---|---|---|
toString | — | Convert to string |
toNumber | — | Parse as number |
toBoolean | — | Parse as boolean |
toDate | format? | Parse as date |
round | decimals?, mode? | Round number (round / ceil / floor) |
trim | — | Trim whitespace |
lowercase | — | Convert to lowercase |
uppercase | — | Convert to uppercase |
default | value | Replace null / undefined |
split | separator | String to array |
join | separator | Array to string |
truncate | length | Limit string length |
replace | pattern, replacement | Regex replace |
custom | body | Inline function body (advanced) |
Null handling
nullAs and undefinedAs per-field, plus nullValues at the lens level, control how
SemiLayer treats missing data at ingest time.
Operations
A lens exposes a fixed set of operations: search, similar, query, and any
named feeds you declare under feeds. Each operation is enabled by adding a
grant under grants.<op>. The embedding inputs for search and similar
come from the searchable flag on each field — per-field weighting via
searchable: { weight: N }. Search mode is a request-time choice:
Post-mapping projection is also request-time — pass fields: ['title', 'body']
to search, similar, query, feed, or their stream variants to shape the
response payload.
Relations
Lenses can declare relations to other lenses, including across different sources. The
join planner resolves them at request time when callers pass an include clause to
search, query, similar, stream.search, or stream.query.
hasMany returns an array per parent row; belongsTo returns at most one. The on
mapping is { [localColumn]: foreignColumn }. See Joins for the full reference
including cross-source patterns and access-rule composition.
Sync configuration
Keep the index fresh as your source data changes.
syncInterval — Periodic incremental sync (fast, cheap, no deletes).
Valid values: '1m' | '5m' | '15m' | '30m' | '1h' | '6h' | '24h'.
smartSyncInterval — Scheduled smart sync with tombstone detection.
Same 7 values. Runs a full-table scan with content-hash dedup on top of the
same handler the Console "Sync now" button uses. Independent of syncInterval
— pair them for comprehensive auto-freshness:
Subject to tier floor and monthly cap — see Keeping data fresh.
changeTrackingColumn — The column used to detect new/updated rows during
incremental sync. Defaults to updated_at.
For change-driven (rather than poll-driven) ingestion, see the ingest webhook flow
under Push & Ingest — push records as they change with an
ik_ ingest key.
Grants (access rules)
See Auth & RBAC for the full reference. Quick example:
query is off by default — set a grant to enable the /v1/query/:lens route.
Auth
Configure JWKS validation for end-user JWTs. This enables 'authenticated' grants and
function grants that receive user claims.
The same fields can be configured per-environment via the Console / CLI without touching
sl.config.ts. JWKS pulled from the file is the developer-experience path; JWKS pulled
from the platform is the production-rotation path.
Complete example
Drift detection
When you run semilayer push, SemiLayer hashes your lens config and compares it against
the last pushed hash. If the config drifted, the CLI flags it:
Changes to fields (adding, removing, or changing a searchable field) require a
rebuild because the embedding text changed. Changes to grants, feeds,
syncInterval, or smartSyncInterval take effect immediately without a rebuild —
the tick handler picks them up on the next pass.