In this quickstart, you’ll create a real-time data pipeline that streams changes from a Postgres database to a Typesense collection. You’ll:

  • Boot Sequin
  • Connect to a sample playground database
  • Create a Typesense collection
  • Set up a sink to sync changes to Typesense
  • See your changes flow in real-time

By the end, you’ll have hands-on experience setting up Postgres change data capture (CDC) with Sequin and Typesense. This same pattern can be used to setup your own Postgres CDC pipeline with Typesense.

Run Sequin

The easiest way to get started with Sequin is with our Docker Compose file. This file starts a Postgres database, Redis instance, and Sequin server.

1

Create directory and start services

  1. Download sequin-docker-compose.zip.
  2. Unzip the file.
  3. Navigate to the unzipped directory and start the services:
cd sequin-docker-compose && docker compose up -d
2

Verify services are running

Check that Sequin is running using docker ps:

docker ps

You should see output like the following:

CONTAINER ID   IMAGE         STATUS         PORTS                      NAMES
2fd334a873e1   redis:7       Up 9 seconds   127.0.0.1:6379->6379/tcp   sequin-dev-redis-1
bf4119bf250f   postgres:17   Up 9 seconds   127.0.0.1:5432->5432/tcp   sequin-dev-postgres-1

All three containers should be up and running (status: Up).

Login

The Docker Compose file automatically configures Sequin with an admin user and a playground database.

Let’s log in to the Sequin web console:

1

Open the web console

After starting the Docker Compose services, open the Sequin web console at http://localhost:7376:

2

Login with default credentials

Use the following default credentials to login:

  • Email:
admin@sequinstream.com
  • Password:
sequinpassword!

View the playground database

To get you started quickly, Sequin’s Docker Compose file creates a logical database called sequin_playground with a sample dataset in the public.products table.

Let’s take a look:

1

Navigate to Databases

In the Sequin web console, click Databases in the sidebar.

2

Select playground database

Click on the pre-configured sequin-playground database:

The database “Health” should be green.

3

View contents of the products table

Let’s get a sense of what’s in the products table. Run the following command:

docker exec -i sequin-sequin_postgres-1 \
  psql -U postgres -d sequin_playground -c \
  "select id, name, price from products;"

This command connects to the running Postgres container and runs a psql command.

You should see a list of the rows in the products table:

  id |         name          | price 
----+-----------------------+-------
  1 | Avocados (3 pack)     |  5.99
  2 | Flank Steak (1 lb)    |  8.99
  3 | Salmon Fillet (12 oz) | 14.99
  4 | Baby Spinach (16 oz)  |  4.99
  5 | Sourdough Bread       |  6.99
  6 | Blueberries (6 oz)    |  3.99
(6 rows)

We’ll make modifications to this table in a bit.

Create a Typesense Collection

First, let’s start Typesense and create a collection to store our product data:

1

Start Typesense

Typesense offers a docker image that can be run locally. Let’s start it up:

docker run -d \
  --name typesense-server \
  -p 8108:8108 \
  -v ./typesense-data:/data \
  --restart on-failure \
  typesense/typesense:28.0 \
  --data-dir /data \
  --api-key=your-api-key \
  --enable-cors
2

Create the collection

Run the following command to create a new collection called “products”:

curl -X POST http://localhost:8108/collections \
  -H "Content-Type: application/json" \
  -H "X-TYPESENSE-API-KEY: your-api-key" \
  -d '{
    "name": "products",
    "fields": [
      {"name": ".*", "type": "auto" }
    ]
  }'

This creates a collection that will automatically detect field types from our data.

3

Verify the collection

You can verify the collection was created by searching it:

curl -X GET "http://localhost:8108/collections/products/documents/search?q=*" \
  -H "X-TYPESENSE-API-KEY: your-api-key"

The collection should be empty initially.

{
  "found": 0,
  "hits": [],
  "out_of": 6,
  "page": 1
}

Create a Typesense Sink

With the playground database connected and Typesense collection created, you can create a sink. This sink will send changes to the products table to your Typesense collection:

1

Navigate to Sinks

Click “Sinks” in the sidebar navigation, then click “Create Sink”.

2

Select sink type

Select “Typesense” as the sink type and click “Continue”.

3

Note "Source" configuration

In the “Source” card, note that the sequin-playground database and products table are pre-selected. Leave these defaults:

4

Setup a transform

In the Transform card, click the toggle to view existing transforms. None exist, so click the ”+” icon which will open a window for creating a new transform.

Select “Function transform” and input the following code:

def transform(action, record, changes, metadata) do
  Map.take(record, ["id", "name", "price"])
end

This transform will take the id, name, and price fields from the products table and use them to create a new document in Typesense.

5

Setup a backfill

In the “Initial backfill” card, click the toggle to enable an initial backfill. You can leave the default start position, which will backfill all existing rows in the products table:

6

Configure Typesense

In the Typesense card, enter your Typesense configuration:

  • Host: http://localhost:8108
  • API Key: your-api-key
  • Collection: products

You can leave the rest of the defaults.

7

Create the sink

You can leave the rest of the defaults. As configured, the Typesense collection will first receive a backfill of all rows currently in the products table. Then, it will receive all changes to the products table in real-time.

Click “Create Sink” to finish setting up your Typesense sync.

Query your data in Typesense

With our initial backfill complete, we can now query Typesense for our products collection:

curl -X GET "http://localhost:8108/collections/products/documents/search?q=*" \
  -H "X-TYPESENSE-API-KEY: your-api-key"

This query will return all documents in the products collection.

To query for just products matching “avocado”, we can add a name parameter to the query:

curl -X GET "http://localhost:8108/collections/products/documents/search?q=avocado&query_by=name" \
    -H "X-TYPESENSE-API-KEY: your-api-key"

This query returns all documents in the products collection where the name field matches “avocado”.

See changes flow to Typesense

On the new sink’s overview page, you should see the “Health” status turn green, indicating data is flowing to Typesense.

Let’s confirm data is flowing by making some changes and searching in Typesense:

1

Make some changes

Let’s make some changes to the products table and see them flow to Typesense.

In your terminal, run the following command to insert a new row into the products table:

docker exec -i sequin-sequin_postgres-1 \
  psql -U postgres -d sequin_playground -c \
  "insert into products (name, price) values ('Organic Honey (16 oz)', 12.99);"

After a few seconds, search for the new product in Typesense:

curl -X GET "http://localhost:8108/collections/products/documents/search?q=honey&query_by=name" \
  -H "X-TYPESENSE-API-KEY: your-api-key"

You should see the new product appear in the search results.

Feel free to try other changes:

Each change will be reflected in Typesense within a few seconds. Try searching for the modified or deleted products to verify the changes.

2

Try fuzzy search

Typesense supports fuzzy search with typo tolerance. Try searching with a typo:

curl -X GET "http://localhost:8108/collections/products/documents/search?q=steak&query_by=name&num_typos=1" \
  -H "X-TYPESENSE-API-KEY: your-api-key"

Even with a typo, you should still find relevant products.

Great work!

You’ve successfully:

  • Set up a complete Postgres change data capture pipeline
  • Created a Typesense collection
  • Loaded existing data through a backfill
  • Made changes to the products table
  • Verified changes are flowing to Typesense
  • Tested search functionality

Ready to stream

Now you’re ready to connect your own database to Sequin and start streaming changes: