> ## Documentation Index
> Fetch the complete documentation index at: https://sequinstream.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Get started with Typesense

> Learn how to create real-time search indexes from Postgres changes in minutes. Use Sequin to keep your Typesense collections in sync with your database.

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.

<Tip>
  This is the quickstart for streaming Postgres to Typesense. See the [how-to guide](/how-to/stream-postgres-to-typesense) for an explanation of how to use the Typesense sink or the [reference](/reference/sinks/typesense) for details on all configuration options.
</Tip>

<Steps titleSize="h2">
  <Step title="Run Sequin" icon="server">
    The easiest way to get started with Sequin is with our [Docker Compose file](https://github.com/sequinstream/sequin/blob/main/docker/docker-compose.yaml). This file starts a Postgres database, Redis instance, and Sequin server.

    <Steps>
      <Step title="Create directory and start services">
        1. Download [sequin-docker-compose.zip](https://github.com/sequinstream/sequin/releases/latest/download/sequin-docker-compose.zip).
        2. Unzip the file.
        3. Navigate to the unzipped directory and start the services:

        ```bash theme={null}
        cd sequin-docker-compose && docker compose up -d
        ```

        <AccordionGroup>
          <Accordion title="Alternative: Download with curl">
            ```bash theme={null}
            curl -L https://github.com/sequinstream/sequin/releases/latest/download/sequin-docker-compose.zip -o sequin-docker-compose.zip \
              && unzip sequin-docker-compose.zip && rm sequin-docker-compose.zip
            cd sequin-docker-compose && docker compose up -d
            ```
          </Accordion>

          <Accordion title="Alternative: Clone the repository">
            ```bash theme={null}
            git clone git@github.com:sequinstream/sequin.git
            cd sequin/docker
            docker compose up -d
            ```
          </Accordion>
        </AccordionGroup>
      </Step>

      <Step title="Verify services are running">
        Check that Sequin is running using `docker ps`:

        ```bash theme={null}
        docker ps
        ```

        You should see output like the following:

        ```
        CONTAINER ID   IMAGE                           COMMAND                  CREATED          STATUS                    PORTS                              NAMES
        bd5c458cabde   sequin/sequin:latest            "/scripts/start_comm…"   11 seconds ago   Up 9 seconds              4000/tcp, 0.0.0.0:7376->7376/tcp   sequin-sequin-1
        3bacd89765e7   grafana/grafana                 "/run.sh"                11 seconds ago   Up 11 seconds             0.0.0.0:3000->3000/tcp             sequin-sequin_grafana-1
        3ad41319a66c   postgres:16                     "docker-entrypoint.s…"   11 seconds ago   Up 11 seconds (healthy)   0.0.0.0:7377->5432/tcp             sequin-sequin_postgres-1
        6139a5fc4e80   redis:7                         "docker-entrypoint.s…"   11 seconds ago   Up 11 seconds             0.0.0.0:7378->6379/tcp             sequin-sequin_redis-1
        7e07a5b052de   prom/prometheus                 "/bin/prometheus --c…"   11 seconds ago   Up 11 seconds             0.0.0.0:9090->9090/tcp             sequin-sequin_prometheus-1
        ```

        <Check>
          Sequin, Postgres, Redis, Prometheus, and Grafana should be up and running (status: `Up`).
        </Check>
      </Step>
    </Steps>
  </Step>

  <Step title="Login" icon="key">
    The Docker Compose file automatically configures Sequin with an admin user and a playground database.

    Let's log in to the Sequin web console:

    <Steps>
      <Step title="Open the web console">
        After starting the Docker Compose services, open the Sequin web console at [http://localhost:7376](http://localhost:7376):

        <Frame>
          <img src="https://mintcdn.com/sequinstream/drUA755uMUeIaCSH/images/quickstart/login-page.png?fit=max&auto=format&n=drUA755uMUeIaCSH&q=85&s=c5d90b34f56560570696a71370f7e39b" alt="Sequin login page, allowing login with default credentials" width="2070" height="1696" data-path="images/quickstart/login-page.png" />
        </Frame>
      </Step>

      <Step title="Login with default credentials">
        Use the following default credentials to login:

        * Email:

        ```
        admin@sequinstream.com
        ```

        * Password:

        ```
        sequinpassword!
        ```
      </Step>
    </Steps>
  </Step>

  <Step title="View the playground database" icon="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:

    <Steps>
      <Step title="Navigate to Databases">
        In the Sequin web console, click **Databases** in the sidebar.
      </Step>

      <Step title="Select playground database">
        Click on the pre-configured `sequin-playground` database:

        <Frame>
          <img src="https://mintcdn.com/sequinstream/drUA755uMUeIaCSH/images/quickstart/playground-database.png?fit=max&auto=format&n=drUA755uMUeIaCSH&q=85&s=01ac1cbf4506cad22c270adb66c0b171" alt="Playground database" width="3376" height="2020" data-path="images/quickstart/playground-database.png" />
        </Frame>

        <Check>
          The database "Health" should be green.
        </Check>
      </Step>

      <Step title="View contents of the products table">
        Let's get a sense of what's in the `products` table. Run the following command:

        ```bash theme={null}
        docker exec -i sequin-sequin_postgres-1 \
          psql -U postgres -d sequin_playground -c \
          "select id, name, price from products;"
        ```

        <Info>
          This command connects to the running Postgres container and runs a `psql` command.
        </Info>

        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.
      </Step>
    </Steps>
  </Step>

  <Step title="Create a Typesense Collection" icon="database">
    First, let's start Typesense and create a collection to store our product data:

    <Steps>
      <Step title="Start Typesense">
        Typesense offers a docker image that can be run locally. Let's start it up:

        ```bash theme={null}
        docker run -d \
          --name typesense-server \
          -p 8108:8108 \
          -v ./typesense-data:/data \
          --restart on-failure \
          typesense/typesense:29.0 \
          --data-dir /data \
          --api-key=my-api-key \
          --enable-cors
        ```
      </Step>

      <Step title="Create the collection">
        Run the following command to create a new collection called "products":

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

        This creates a collection that will automatically detect field types from our data.
      </Step>

      <Step title="Verify the collection">
        You can verify the collection was created by searching it:

        ```bash theme={null}
        curl -X GET "http://localhost:8108/collections/products/documents/search?q=*" \
          -H "X-TYPESENSE-API-KEY: my-api-key"
        ```

        The collection should be empty initially.

        ```
        {
          "found": 0,
          "hits": [],
          "out_of": 6,
          "page": 1
        }
        ```
      </Step>
    </Steps>
  </Step>

  <Step title="Create a Typesense Sink" icon="plug">
    With the playground database connected and Typesense collection created, you can create a [sink](/reference/sinks/overview). This sink will send changes to the `products` table to your Typesense collection:

    <Steps>
      <Step title="Navigate to Sinks">
        Click "Sinks" in the sidebar navigation, then click "Create Sink".
      </Step>

      <Step title="Select sink type">
        Select "Typesense" as the sink type and click "Continue".
      </Step>

      <Step title="Note &#x22;Source&#x22; configuration">
        In the "Source" card, note that the `sequin-playground` database is selected and all schemas and tables are included. Leave these defaults:

        <Frame>
          <img style={{ maxWidth: '500px' }} src="https://mintcdn.com/sequinstream/I2Yx_f_pmUFGglUP/images/quickstart/source-card.png?fit=max&auto=format&n=I2Yx_f_pmUFGglUP&q=85&s=a1ba47d0e4698d439d64db0d582f0951" alt="Source card showing the sequin_playground database and products table" width="1640" height="778" data-path="images/quickstart/source-card.png" />
        </Frame>
      </Step>

      <Step title="Setup a transform">
        In the [Transform](/reference/transforms) card, click the toggle to view existing transforms. None exist, so click "+ Create new transform" which will open a window for creating a new transform.

        For "Transform name", put `products-typesense`. For "Transform type", select "Transform function".

        In the "Transform function" field, input the following code:

        ```elixir theme={null}
        def transform(action, record, changes, metadata) do
          record
          |> Map.take(["id", "name", "price"])
          # Typesense requires `id` to be a string
          |> Map.update("id", nil, fn id ->
            cond do
              is_binary(id) -> id
              is_integer(id) -> Integer.to_string(id)
              true -> to_string(id)
            end
          end)
        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.

        <Frame>
          <img src="https://mintcdn.com/sequinstream/I2Yx_f_pmUFGglUP/images/quickstart/typesense/transform-card.png?fit=max&auto=format&n=I2Yx_f_pmUFGglUP&q=85&s=c3d511e7ac1fd08aafed749350f6d110" alt="Transform card with Elixir transform" width="1722" height="1252" data-path="images/quickstart/typesense/transform-card.png" />
        </Frame>

        Click "Create Transform".

        You can close the transform tab and navigate back to the Typesense sink create page.

        Now, select the `products-typesense` transform in the "Transform" list. (If you don't see it, click the refresh icon.)
      </Step>

      <Step title="Setup a backfill">
        In the `Inital backfill` card, select the `public.products` table to initate a backfill when the sink is created.

        <Frame>
          <img style={{ maxWidth: '700px' }} src="https://mintcdn.com/sequinstream/drUA755uMUeIaCSH/images/quickstart/backfill-card.png?fit=max&auto=format&n=drUA755uMUeIaCSH&q=85&s=2a41931bc2d650f7467f3c7ae92b5b0a" alt="Initial backfill card with public.products table selected" width="1606" height="570" data-path="images/quickstart/backfill-card.png" />
        </Frame>
      </Step>

      <Step title="Configure Typesense">
        In the Typesense card, enter your Typesense configuration:

        * Host: `http://host.docker.internal:8108`
          * If that doesn't work, your host and port may be `http://typesense-server:8108`
        * Collection: `products`
        * API Key: `my-api-key`

        You can leave the rest of the defaults.

        <Frame>
          <img src="https://mintcdn.com/sequinstream/I2Yx_f_pmUFGglUP/images/quickstart/typesense/config-card-2.png?fit=max&auto=format&n=I2Yx_f_pmUFGglUP&q=85&s=3e9bd5189ad9af0c969cea06620b5ecc" alt="Typesense configuration card" width="1614" height="1200" data-path="images/quickstart/typesense/config-card-2.png" />
        </Frame>
      </Step>

      <Step title="Create the sink">
        Give your sink a name, like `products-typesense`, and click "Create Sink".

        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.
      </Step>
    </Steps>
  </Step>

  <Step title="Query your data in Typesense" icon="waveform-lines">
    With our initial backfill complete, we can now query Typesense for our `products` collection:

    ```bash theme={null}
    curl -X GET "http://localhost:8108/collections/products/documents/search?q=*" \
      -H "X-TYPESENSE-API-KEY: my-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:

    ```bash theme={null}
    curl -X GET "http://localhost:8108/collections/products/documents/search?q=avocado&query_by=name" \
        -H "X-TYPESENSE-API-KEY: my-api-key"
    ```

    This query returns all documents in the `products` collection where the `name` field matches "avocado".
  </Step>

  <Step title="See changes flow to Typesense" icon="waveform-lines">
    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:

    <Steps>
      <Step title="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:

        ```bash theme={null}
        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:

        ```bash theme={null}
        curl -X GET "http://localhost:8108/collections/products/documents/search?q=honey&query_by=name" \
          -H "X-TYPESENSE-API-KEY: my-api-key"
        ```

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

        Feel free to try other changes:

        <AccordionGroup>
          <Accordion title="Update a product's price">
            ```bash theme={null}
            docker exec -i sequin-sequin_postgres-1 \
              psql -U postgres -d sequin_playground -c \
              "update products set price = 7.99 where name = 'Avocados (3 pack)';"
            ```
          </Accordion>

          <Accordion title="Change a product's name">
            ```bash theme={null}
            docker exec -i sequin-sequin_postgres-1 \
              psql -U postgres -d sequin_playground -c \
              "update products set name = 'Organic Avocados (3 pack)' where name = 'Avocados (3 pack)';"
            ```
          </Accordion>

          <Accordion title="Delete a product">
            ```bash theme={null}
            docker exec -i sequin-sequin_postgres-1 \
              psql -U postgres -d sequin_playground -c \
              "delete from products where name = 'Blueberries (6 oz)';"
            ```
          </Accordion>
        </AccordionGroup>

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

      <Step title="Try fuzzy search">
        Typesense supports fuzzy search with typo tolerance. Try searching with a typo:

        ```bash theme={null}
        curl -X GET "http://localhost:8108/collections/products/documents/search?q=steak&query_by=name&num_typos=1" \
          -H "X-TYPESENSE-API-KEY: my-api-key"
        ```

        Even with a typo, you should still find relevant products.
      </Step>
    </Steps>
  </Step>
</Steps>

<Check>
  Great work!
</Check>

You've successfully:

* 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
* Set up a complete Postgres change data capture pipeline

## Ready to stream

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

<CardGroup cols={2}>
  <Card title="Guide: Connect Postgres" icon="elephant" href="/connect-postgres">
    Connect your Postgres database to Sequin.
  </Card>

  <Card title="Guide: Setting up a Typesense sink" icon="search" href="/how-to/stream-postgres-to-typesense">
    Setup a Typesense sink to keep your search index in sync.
  </Card>
</CardGroup>
