Sinks
A sink is where Wallaby delivers your transformed documents. Wallaby ships sinks for Meilisearch, Elasticsearch, OpenSearch, Kafka, pgvector and HTTP webhooks, and you can deliver anywhere else by implementing ISink.
A single Wallaby host can run several sinks at once. They share one replication slot and one publication, so adding a second destination costs no extra load on Postgres.
Choosing a destination
| Destination | Package | Reach for it when | NativeAOT |
|---|---|---|---|
| Meilisearch | Wallaby.Sinks.Meilisearch | Fast typo-tolerant product or in-app search | no (client SDK) |
| Elasticsearch | Wallaby.Sinks.Elasticsearch | Search plus analytics, self-managed or Elastic Cloud | no (client SDK) |
| OpenSearch | Wallaby.Sinks.OpenSearch | AWS-managed search (Amazon OpenSearch Service) | no (client SDK) |
| Kafka | Wallaby.Sinks.Kafka | Fanning changes out to other services | yes |
| pgvector | Wallaby.Sinks.Pgvector | A RAG corpus that stays inside Postgres | yes |
| HTTP | Wallaby.Sinks.Http | Anything that exposes an endpoint | yes |
| Custom | n/a | Everything else | your call |
Meilisearch, Elasticsearch and OpenSearch depend on client SDKs that are not trim- or NativeAOT-safe. All other packages are marked IsAotCompatible. See each page's NativeAOT section for the SerializerOptions a trimmed host needs.
If you are keeping embeddings fresh rather than building a search index, start at RAG & Embeddings, which covers when to let the destination own embedding and when to do it in the sink.
Sink guarantees
These apply to all sinks regardless of what you pick:
- At-least-once delivery. The replication slot only advances after a batch is durably delivered, so a crash can redeliver the last batch. Every built-in sink upserts and deletes by a stable document id.
- Commit order. Changes are delivered in the order Postgres committed them, and batches that get split into several requests preserve that order.
- One slot, one ack point. Every sink on a host reads the same replication stream. Wallaby only acknowledges once the batch has reached all of them.
- Backfill seeding. A new destination is seeded by backfill, which runs concurrently with the live stream and merges with it, so there are no gaps and no stale overwrites.
- Purge-then-backfill. Bumping a mapping's backfill version with
purgeOnChange: trueempties the destination before rebuilding it, which is how you reshape a document or re-embed a corpus. - Permanent failures halt the pipeline. A misconfiguration or a payload the destination will never accept stops the pipeline rather than silently skipping records. Transient failures retry with exponential backoff.
Future plans
There is no built-in sink for Typesense, Algolia, Redis, MongoDB or SQL Server, although these are planned for the future. Any of them is reachable today through a custom ISink, which is a small interface, and sink contributions are welcome.
Write your own
Custom sinks covers the ISink contract: batch delivery, how to classify a failure as retryable or permanent, one-time setup, and purge support.