1. Provision the target (one-time)
VentStream never needs root. In Surrealist (or any client with admin authority — for a local instance,surreal sql -u root -p root works), create the namespace, database,
and a database-scoped user:
/signin; the sink handles tokens and refresh automatically. If the
database is missing at startup, the sink fails with exactly this DDL in
the error message. (For a throwaway local instance you can instead set
auto_create_database: true and connect with root — dev only.)
2. A complete pipeline
The sink is one half of a pipeline file; any source provides the other. A minimal, complete Postgres → SurrealDB config:*_ref: env:NAME resolves each value from the environment at startup,
so no secret lives in the file. Export them and run the engine:
public.orders lands in table orders — and
table_prefix: "pg-" would make that pg-orders. Verify in Surrealist:
Record identity
VentStream’s deterministic doc idtable:["pk",…] maps directly onto
SurrealDB’s array record ids — orders:['299'], composite keys included
— so upserts are idempotent and deletes always find their record. The
canonical id is stamped on every document as _vs_id. A source column
named id is preserved as source_id (SurrealDB reserves id for the
record id itself).
Vector search
Declare embedding fields to make them KNN-searchable — the sink ensures the HNSW index at startup:WHERE embedding <|10,40|> $vec.
Large joined tables
For 1:many joined pipelines, declare the embedded join paths so child deletes filter a flat materialized field instead of evaluating a per-row closure (~5x cheaper today, index-ready in future SurrealDB versions):Semantics to know
- Concurrent writers converge. SurrealDB uses optimistic transactions; the sink classifies conflicts as transient and retries the ordered tail — replays are idempotent, so external writers hammering the same records cost retries, not corruption.
- Full-replace materialization. Documents are replaced, not merged: fields written by other applications on the same records are overwritten on the next sync. Give VentStream its own tables.
table_routing.mode: fixedfunnels every relation into one named table (records keep fully-qualified ids so relations can’t collide); a TRUNCATE of any relation then clears that shared table — prefer the default per-relation routing unless you need this.
Troubleshooting
namespace/database is not provisioned— run the DDL from step 1, or setauto_create_database: truewith elevated credentials (dev only).HTTP 401at startup — wrong credentials, or the user was defined at a different scope than the configured namespace/database.- Writes retry with
transient statement failure— normal under write contention; sustained retries mean another process is hammering the same records.