You read data from Sequin via consumers. Consumers guarantee at-least-once delivery. This means that with the right upsert logic, you can be confident that your database completely matches the state of the API.Documentation Index
Fetch the complete documentation index at: https://sequin.io/docs/llms.txt
Use this file to discover all available pages before exploring further.
Schema design
By letting you control the schema of your Postgres tables, Sequin makes it easy for you to manage things like table design, migrations, and transforms in your preferred programming language and ORM. A Sequin record contains a number of standard fields plus all the API-specific fields for a given collection. It’s usually a good idea to store a few of these standard fields as columns in each table:| Field Name | Type | Description |
|---|---|---|
id | text | The unique ID of the record. This ID is unique across syncs and providers. You can use this as the primary key in your database. |
upstream_id | text | The ID of the record in the API. Useful for relationships between tables. |
deleted | boolean | Whether the record has been deleted in the API. |
updated_idx | bigint | A sequential index that increments every time the record is updated. Indicates the version of the record. See advanced below for ways you can leverage this field. |
sync.id | text | The ID of the sync this record belongs to. |
sync.external_id | text | The external_id of the sync this record belongs to. You can set external_id to any text value you’d like to correlate a sync to a user or account in your system. |
sync.metadata | jsonb | The metadata of the sync this record belongs to. You can store any information you’d like in metadata in order to correlate a sync to a user or account in your system. |
create table statement that leverages a record’s fields might look like this:
Upserting
Each record in Sequin has acollection_slug that you can use to determine which table it belongs to.
In raw SQL, an upsert of Sequin data into a table might look like this:
Soft deletes vs hard deletes
Sequin’s records each have adeleted property. When a record is deleted in the API, Sequin sets deleted to true.
You can “soft delete” records in your system by simply upserting deleted records (and setting e.g. deleted to true). Alternatively, you can drop records from your database when they are deleted in the API.
Examples
See the sidebar for examples in various programming languages and ORMs.Advanced upserts
We recommend you only worry about this advanced feature after you’re up and running in production with Sequin.
ack_wait of 60s. That means that delivered messages will be delivered after 60s if they’re not ack’d. If your workers are not configured with hard timeouts, the following can occur:
- Worker 1 retrieves message
A. - While Worker 1 is processing its message,
Ais updated in the API and becomesA'. Sequin continues to withhold delivery of the message. - Worker 1 is taking a long time to process. 60s elapse.
- The
ack_waitfor the message expires, so Sequin deliversA'to Worker 2. - Worker 2 upserts
A'. - Worker 1 finally completes processing
Aand upsertsA.
where clause in the upsert prevents old records from overwriting new ones.
Some ORMs support where clauses in upserts, and when they do we showcase it in our examples for that ORM. But most ORMs don’t support this Postgres feature. So, if you want to implement this extra protection and your ORM doesn’t support it, you can use a slightly different strategy:
- Open a transaction.
- Select the record you’re going to upsert
for update. This will lock the record for the duration of the transaction. - If the record exists, compare
updated_idxto the new record’supdated_idx. Proceed with the update if the incoming record is newer. - If the record doesn’t exist, insert it.
- Close the transaction.

