Getting Started Guide - v0.13.0

Version:

Let's begin by installing Typesense, indexing some documents and exploring the data with some search queries.

For a detailed dive into the Typesense API, refer to our API documentation.

Installing Typesense

You can find DEB, RPM and pre-built binaries available for Linux (X86_64) and Mac OS X on our downloads page.

We also publish official Docker images for Typesense on Docker hub.

DEB package on Ubuntu/Debian
apt install ./typesense-server-<version>-amd64.deb
RPM package on CentOS/RHEL
yum install ./typesense-server-<version>.x86_64.rpm

Starting the Typesense server

NOTE: We are starting a single node here, but Typesense can also run in a clustered mode. See the high availability section for more details.

Installed via the package manager

If you had installed Typesense from a DEB/RPM package, the Typesense server is automatically started as a systemd service when installation is complete. You can check the status via:

systemctl status typesense-server

By default, Typesense will start on port 8108, and the installation will generate a random API key, which you can view/change from the configuration file at /etc/typesense/typesense.ini

From the pre-built binary

If you have downloaded the pre-built binary, you can start Typesense with minimal options like this:

mkdir /tmp/typesense-data
./typesense-server --data-dir=/tmp/typesense-data --api-key=$TYPESENSE_API_KEY

From the docker image

If you want to use Docker, you can run Typesense like this:

mkdir /tmp/typesense-data
docker run -p 8108:8108 -v/tmp/typesense-data:/data typesense/typesense:0.14.0 \
  --data-dir /data --api-key=$TYPESENSE_API_KEY

You can use the /health API end-point to verify that the server is ready to accept requests.

curl http://localhost:8108/health
{"ok":true}

Server arguments

Parameter Required Description
config false Path to the configuration file. If you use this argument, you can define all of the other command line arguments in a configuration file. See the "Configuring Typesense" section for more details.
api-key true

A bootstrap admin API key that allows all operations. Be sure to create additional keys with specific ACLs using the key management API.

NOTE: Don't expose this admin API key to your browser JS client: use the key management API to create search-only or scoped API keys.

data-dir true Path to the directory where data will be stored on disk.
api-address false Address to which Typesense API service binds. Default: 0.0.0.0
api-port false Port on which Typesense API service listens. Default: 8108
peering-address false Internal IP address to which Typesense peering service binds. If this parameter is not specified, Typesense will attempt to use the first available internal IP.
peering-port false Port on which Typesense peering service listens. Default: 8107
nodes false

Path to file containing comma separated string of all nodes in the cluster. Each node definition should be in the following format:

<ip_address>:<peering_port>:<api_port>

Example content of a --nodes file for a 3-node cluster:

192.168.12.1:8107:8108,192.168.12.2:8107:8108,192.168.12.3:8107:8108

log-dir false By default, Typesense logs to stdout and stderr. To enable logging to a file, provide a path to a logging directory.
ssl-certificate false Path to the SSL certificate file. You must also define ssl-certificate-key to enable HTTPS.
ssl-certificate-key false Path to the SSL certificate key file. You must also define ssl-certificate to enable HTTPS.
enable-cors false Allow Javascript client to access Typesense directly from the browser.

Configuring Typesense

As an alternative to command line arguments, you can also configure Typesense server through a configuration file or via environment variables.

Command line arguments are given the highest priority, while environment variables are given the least priority.

Using a configuration file

Let's see how we can use a configuration file first:

./typesense-server --config=/etc/typesense/typesense-server.ini

Our Linux DEB/RPM packages install the configuration file at /etc/typesense/typesense-server.ini.

The configuration file uses a simple INI format:

; /etc/typesense/typesense-server.ini

[server]

api-key = Rhsdhas2asasdasj2
data-dir = /tmp/ts
log-dir = /tmp/logs
api-port = 9090

Using environment variables

If you wish to use environment variables, you can do that too. The environment variables map to the command line arguments documented above: just use CAPS and underscores instead of hyphens, and prefix the variable names with TYPESENSE_.

For example, use TYPESENSE_DATA_DIR for the --data-dir argument.

TYPESENSE_DATA_DIR=/tmp/ts TYPESENSE_API_KEY=AS3das2awQ2 ./typesense-server

Installing a client

At the moment, we have clients for Javascript, Python, and Ruby.

We recommend that you use our API client if it's available for your language. It's also easy to interact with Typesense through its simple, RESTful HTTP API.

gem install typesense
pip install typesense
// Node.js
npm install typesense

// Browser
<script src="dist/typesense.min.js"></script>

Example application

NOTE: We will be using a single node in this example, but Typesense can also run in a clustered mode. See the high availability section for more details.

At this point, we are all set to start using Typesense. We will create a Typesense collection, index some documents in it and try searching for them.

To follow along, download this small dataset that we've put together for this walk-through.

Initializing the client

Let's begin by configuring the Typesense client by pointing it to the Typesense master node.

Be sure to use the same API key that you used to start the Typesense server earlier.

require 'typesense'

client = Typesense::Client.new(
  nodes: [{
    host:     'localhost',
    port:     8108,
    protocol: 'http'
  }],
  api_key:  '<API_KEY>',
  connection_timeout_seconds: 2
)
import typesense

client = typesense.Client({
  'nodes': [{
    'host': 'localhost',
    'port': '8108',
    'protocol': 'http'
  }],
  'api_key': '<API_KEY>',
  'connection_timeout_seconds': 2
})
/*
 *  Our Javascript client library works on both the client and the browser.
 *  When using the library on the browser, please be sure to use the
 *  search-only API Key rather than the master API key since the latter
 *  has write access to Typesense and you don't want to expose that.
 */
let client = new Typesense.Client({
  'nodes': [{
    'host': 'localhost',
    'port': '8108',
    'protocol': 'http'
  }],
  'apiKey': '<API_KEY>',
  'connectionTimeoutSeconds': 2
})
export TYPESENSE_API_KEY='<API_KEY>'
export TYPESENSE_MASTER='http://localhost:8108'

That's it - we're now ready to start interacting with the Typesense server.

Creating a "books" collection

In Typesense, a collection is a group of related documents that is roughly equivalent to a table in a relational database. When we create a collection, we give it a name and describe the fields that will be indexed when a document is added to the collection.

require 'typesense'

books_schema = {
  'name' => 'books',
  'fields' => [
    {'name' => 'title', 'type' => 'string' },
    {'name' => 'authors', 'type' => 'string[]' },
    {'name' => 'image_url', 'type' => 'string' },

    {'name' => 'publication_year', 'type' => 'int32' },
    {'name' => 'ratings_count', 'type' => 'int32' },
    {'name' => 'average_rating', 'type' => 'float' },

    {'name' => 'authors_facet', 'type' => 'string[]', 'facet' => true },
    {'name' => 'publication_year_facet', 'type' => 'string', 'facet' => true }
  ],
  'default_sorting_field' => 'ratings_count'
}

client.collections.create(books_schema)
import typesense

books_schema = {
  'name': 'books',
  'fields': [
    {'name': 'title', 'type': 'string' },
    {'name': 'authors', 'type': 'string[]' },
    {'name': 'image_url', 'type': 'string' },

    {'name': 'publication_year', 'type': 'int32' },
    {'name': 'ratings_count', 'type': 'int32' },
    {'name': 'average_rating', 'type': 'float' },

    {'name': 'authors_facet', 'type': 'string[]', 'facet': True },
    {'name': 'publication_year_facet', 'type': 'string', 'facet': True },
  ],
  'default_sorting_field': 'ratings_count'
}

client.collections.create(books_schema)
let booksSchema = {
  'name': 'books',
  'fields': [
    {'name': 'title', 'type': 'string' },
    {'name': 'authors', 'type': 'string[]' },
    {'name': 'image_url', 'type': 'string' },

    {'name': 'publication_year', 'type': 'int32' },
    {'name': 'ratings_count', 'type': 'int32' },
    {'name': 'average_rating', 'type': 'float' },

    {'name': 'authors_facet', 'type': 'string[]', 'facet': true },
    {'name': 'publication_year_facet', 'type': 'string', 'facet': true },
  ],
  'default_sorting_field': 'ratings_count'
}

client.collections().create(booksSchema)
  .then(function (data) {
    console.log(data)
  })
curl "http://localhost:8108/collections" -X POST -H "Content-Type: application/json" \
      -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" -d '{
        "name": "books",
        "fields": [
          {"name": "title", "type": "string" },
          {"name": "authors", "type": "string[]" },
          {"name": "image_url", "type": "string" },

          {"name": "publication_year", "type": "int32" },
          {"name": "ratings_count", "type": "int32" },
          {"name": "average_rating", "type": "float" },

          {"name": "authors_facet", "type": "string[]", "facet": true },
          {"name": "publication_year_facet", "type": "string", "facet": true }
        ],
        "default_sorting_field": "ratings_count"
      }'

For each field, we define its name, type and whether it's a facet field. A facet field allows us to cluster the search results into categories and let us drill into each of those categories. We will be seeing faceted results in action at the end of this guide.

We also define a default_sorting_field that determines how the results must be sorted when no sort_by clause is provided. In this case, books that have more ratings will be ranked higher.

Adding books to the collection

We're now ready to index some books into the collection we just created.

require 'rubygems'
require 'json'
require 'typesense'

File.readlines('/tmp/books.jsonl').each do |json_line|
  book_document = JSON.parse(json_line)
  client.collections['books'].documents.create(book_document)
end
import json
import typesense

with open('/tmp/books.jsonl') as infile:
  for json_line in infile:
    book_document = json.loads(json_line)
    client.collections['books'].documents.create(book_document)
var fs = require('fs');
var readline = require('readline');

readline.createInterface({
    input: fs.createReadStream('/tmp/books.jsonl'),
    terminal: false
}).on('line', function(line) {
   let bookDocument = JSON.parse(line);
   client.collections('books').documents().create(bookDocument)
});
#!/bin/bash
input="/tmp/books.jsonl"
while IFS= read -r line
do
  curl "$TYPESENSE_MASTER/collections/books/documents" -X POST \
  -H "Content-Type: application/json" \
  -H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" \
  -d "$line"
done < "$input"

Searching for books

We will start with a really simple search query - let's search for harry potter and ask Typesense to rank books that have more ratings higher in the results.

search_parameters = {
  'q'         => 'harry potter',
  'query_by'  => 'title',
  'sort_by'   => 'ratings_count:desc'
}

client.collections['books'].documents.search(search_parameters)
search_parameters = {
  'q'         : 'harry',
  'query_by'  : 'title',
  'sort_by'   : 'ratings_count:desc'
}

client.collections['books'].documents.search(search_parameters)
let searchParameters = {
  'q'         : 'harry',
  'query_by'  : 'title',
  'sort_by'   : 'ratings_count:desc'
}

client.collections('books')
  .documents()
  .search(searchParameters)
  .then(function (searchResults) {
    console.log(searchResults)
  })
curl -H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" \
"$TYPESENSE_MASTER/collections/books/documents/search\
?q=harry+potter&query_by=title&sort_by=ratings_count:desc"
Sample response
{
  "facet_counts": [],
  "found": 62,
  "hits": [
    {
      "highlights": [
        {
          "field": "title",
          "snippet": "<mark>Harry</mark> <mark>Potter</mark> and the Philosopher's Stone"
        }
      ],
      "document": {
        "authors": [
          "J.K. Rowling", "Mary GrandPré"
        ],
        "authors_facet": [
          "J.K. Rowling", "Mary GrandPré"
        ],
        "average_rating": 4.44,
        "id": "2",
        "image_url": "https://images.gr-assets.com/books/1474154022m/3.jpg",
        "publication_year": 1997,
        "publication_year_facet": "1997",
        "ratings_count": 4602479,
        "title": "Harry Potter and the Philosopher's Stone"
      }
    },
    ...
  ]
}

In addition to returning the matching documents, Typesense also highlights where the query terms appear in a document via the highlight property.

Want to actually see newest harry potter books returned first? No problem, we can change the sort_by clause to publication_year:desc:

search_parameters = {
  'q'         => 'harry potter',
  'query_by'  => 'title',
  'sort_by'   => 'publication_year:desc'
}

client.collections['books'].documents.search(search_parameters)
search_parameters = {
  'q'         : 'harry',
  'query_by'  : 'title',
  'sort_by'   : 'publication_year:desc'
}

client.collections['books'].documents.search(search_parameters)
let searchParameters = {
  'q'         : 'harry',
  'query_by'  : 'title',
  'sort_by'   : 'publication_year:desc'
}

client.collections('books')
  .documents()
  .search(searchParameters)
  .then(function (searchResults) {
    console.log(searchResults)
  })
curl -H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" \
"$TYPESENSE_MASTER/collections/books/documents/search\
?q=harry+potter&query_by=title&sort_by=publication_year:desc"
Sample response
{
  "facet_counts": [],
  "found": 62,
  "hits": [
  {
    "highlights": [
      {
        "field": "title",
        "snippet": "<mark>Harry</mark> <mark>Potter</mark> and the Cursed Child..."
      }
    ],
    "document": {
      "authors": [
        "John Tiffany", "Jack Thorne", "J.K. Rowling"
      ],
      "authors_facet": [
        "John Tiffany", "Jack Thorne", "J.K. Rowling"
      ],
      "average_rating": 3.75,
      "id": "279",
      "image_url": "https://images.gr-assets.com/books/1470082995m/29056083.jpg",
      "publication_year": 2016,
      "publication_year_facet": "2016",
      "ratings_count": 270603,
      "title": "Harry Potter and the Cursed Child, Parts One and Two"
    }
  },
  ...
  ]
}

Filtering results

Now, let's tweak our query to only fetch books that are published before the year 1998. To do that, we just have to add a filter_by clause to our query:

search_parameters = {
  'q'         => 'harry potter',
  'query_by'  => 'title',
  'filter_by' => 'publication_year:<1998',
  'sort_by'   => 'publication_year:desc'
}

client.collections['books'].documents.search(search_parameters)
search_parameters = {
  'q'         : 'harry',
  'query_by'  : 'title',
  'filter_by' : 'publication_year:<1998',
  'sort_by'   : 'publication_year:desc'
}

client.collections['books'].documents.search(search_parameters)
let searchParameters = {
  'q'         : 'harry',
  'query_by'  : 'title',
  'filter_by' : 'publication_year:<1998',
  'sort_by'   : 'publication_year:desc'
}

client.collections('books')
  .documents()
  .search(searchParameters)
  .then(function (searchResults) {
    console.log(searchResults)
  })
curl -H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" \
"$TYPESENSE_MASTER/collections/books/documents/search\
?q=harry+potter&query_by=title&sort_by=publication_year:desc\
&filter_by=publication_year:<1998"
Sample response
{
  "facet_counts": [],
  "found": 24,
  "hits": [
    {
      "highlights": {
        "title": {
          "field": "title",
          "snippet": "<mark>Harry</mark> <mark>Potter</mark> and the Philosopher's Stone"
        }
      },
      "document": {
        "authors": [
            "J.K. Rowling", "Mary GrandPré"
        ],
        "authors_facet": [
            "J.K. Rowling", "Mary GrandPré"
        ],
        "average_rating": 4.44,
        "id": "2",
        "image_url": "https://images.gr-assets.com/books/1474154022m/3.jpg",
        "publication_year": 1997,
        "publication_year_facet": "1997",
        "ratings_count": 4602479,
        "title": "Harry Potter and the Philosopher's Stone"
      }
    },
    ...
  ]
}

Faceting

Let's facet the search results by the authors field to see how that works. Let's also use this example to see how Typesense handles typographic errors. Let's search for experyment (notice the typo!).

search_parameters = {
  'q'         => 'experyment',
  'query_by'  => 'title',
  'facet_by'  => 'authors_facet',
  'sort_by'   => 'average_rating:desc'
}

client.collections['books'].documents.search(search_parameters)
search_parameters = {
  'q'         : 'experyment',
  'query_by'  : 'title',
  'facet_by' : 'authors_facet',
  'sort_by'   : 'average_rating:desc'
}

client.collections['books'].documents.search(search_parameters)
let searchParameters = {
  'q'         : 'experyment',
  'query_by'  : 'title',
  'facet_by' : 'authors_facet',
  'sort_by'   : 'average_rating:desc'
}

client.collections('books')
  .documents()
  .search(searchParameters)
  .then(function (searchResults) {
    console.log(searchResults)
  })
curl -H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" \
"$TYPESENSE_MASTER/collections/books/documents/search\
?q=experyment&query_by=title&sort_by=average_rating:desc\
&facet_by=authors_facet"

As we can see in the result below, Typesense handled the typographic error gracefully and fetched the results correctly. The facet_by clause also gives us a neat break-down of the number of books written by each author in the returned search results.

Sample response
{
  "facet_counts": [
    {
      "field_name": "authors_facet",
      "counts": [
          {
              "count": 2,
              "value": " Käthe Mazur"
          },
          {
              "count": 2,
              "value": "Gretchen Rubin"
          },
          {
              "count": 2,
              "value": "James Patterson"
          },
          {
              "count": 2,
              "value": "Mahatma Gandhi"
          }
      ]
    }
  ],
  "found": 3,
  "hits": [
    {
      "_highlight": {
        "title": "The Angel <mark>Experiment</mark>"
      },
      "document": {
        "authors": [
            "James Patterson"
        ],
        "authors_facet": [
            "James Patterson"
        ],
        "average_rating": 4.08,
        "id": "569",
        "image_url": "https://images.gr-assets.com/books/1339277875m/13152.jpg",
        "publication_year": 2005,
        "publication_year_facet": "2005",
        "ratings_count": 172302,
        "title": "The Angel Experiment"
      }
    },
    ...
  ]
}

We've come to the end of our little walk-through. For a detailed dive into Typesense, refer to our API documentation.

Building Search UIs

You can use the open source InstantSearch.js library, along with our Typesense-InstantSearch-Adapter to build a plug-and-play full-featured search interface, with just a few lines of code.

Let's start with a starter template:

$ npx create-instantsearch-app typesense-instantsearch-demo

Creating a new InstantSearch app in typesense-instantsearch-demo.

? InstantSearch template InstantSearch.js
? InstantSearch.js version 4.5.0
? Application ID typesense
? Search API key typesense_search_only_api_key
? Index name books
? Attributes to display
  Used to generate the default result template

📦  Installing dependencies...

yarn install v1.22.0
info No lockfile found.
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 🔨  Building fresh packages...
success Saved lockfile.
✨  Done in 24.73s.

🎉  Created typesense-instantsearch-demo at typesense-instantsearch-demo.

Begin by typing:

  cd typesense-instantsearch-demo
  yarn start

⚡️  Start building something awesome!
A couple of setup pointers for the npx create-instantsearch-app command above:
  • InstantSearch template: you can pick any one of the web libraries we support: InstantSearch.js, React, Vue or Angular.
  • InstantSearch.js version: you can leave it at the default
  • Application ID: can be any string - we'll be replacing this later in the guide
  • Search API key: can be any string - we'll be replacing this later in the guide with your Typesense Search-only API Key
  • Index name: the name of your collection in Typesense
  • Attributes to display: leave it as (none)
Let's now install the Typesense InstantSearch adapter, to be able to use InstantSearch with a Typesense backend:
$ npm install --save typesense-instantsearch-adapter
To get InstantSearch.js to use the Typesense adapter, open src/app.js and edit how InstantSearch is initialized, from this:
const searchClient = algoliasearch('typesense', 'typesense_search_only_api_key');

const search = instantsearch({
  indexName: 'books',
  searchClient,
});
to this:
import TypesenseInstantSearchAdapter from "typesense-instantsearch-adapter";

const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter({
  server: {
    apiKey: "abcd", // Be sure to use the search-only-api-key
    nodes: [
      {
        host: "localhost",
        port: "8108",
        protocol: "http"
      }
    ]
  },
  // The following parameters are directly passed to Typesense's search API endpoint.
  //  So you can pass any parameters supported by the search endpoint below. 
  //  queryBy is required. 
  additionalSearchParameters: {
    queryBy: "title,authors"
  }
});
const searchClient = typesenseInstantsearchAdapter.searchClient;

const search = instantsearch({
  searchClient,
  indexName: "books"
});
We're essentially creating a searchClient with the adapter and passing it to instantsearch when initializing it. Now, you can use any of the widgets supported by InstantSearch to build a search interface. In this walkthrough, we'll add a search box, along with results:
search.addWidgets([
  instantsearch.widgets.searchBox({
    container: '#searchbox',
  }),
  instantsearch.widgets.hits({
    container: '#hits',
    templates: {
      item: `
        <div>
          <img src="" align="left" alt="" />
          <div class="hit-name">
            { "attribute": "title" }
          </div>
          <div class="hit-description">
            { "attribute": "authors" }
          </div>
          <div class="hit-price">\$</div>
          <div class="hit-rating">Rating: </div>
        </div>
      `,
    },
  }),
  instantsearch.widgets.pagination({
    container: '#pagination',
  }),
]);

search.start();
Now run npm start to start the dev server and view the app. You should now have a fully-functioning instant search interface with a search box, results that update as you type and pagination.

Demo App

Here's a repo with a working version of the app, following the instructions above: https://github.com/typesense/typesense-instantsearch-demo. The repo also contains quick commands to start a local Typesense server (npm run typesenseServer) and index the books collection used in this example (npm run populateTypesenseIndex).

InstantSearch.js also has React, Vue, Angular cousins. The Typesense InstantSearch adapter is also compatible with them. Similar to the above, you only need to swap the searchClient to the one provided by Typesense adapter. The rest of the instructions found in each of these repos work without additional changes.

Ranking and relevance

Typesense ranks search results using a simple tie-breaking sorting algorithm that can rely on one or more of:

  1. Text match score, exposed as a special _text_match field.
  2. User-defined indexed numerical fields.
Text match score

The text match score is computed based on the following metrics:

  1. Frequency: Number of tokens overlapping between the search query and a text field. Documents that have more overlapping tokens will be ranked above those with lesser overlapping tokens.
  2. Edit distance: If a given token in the query is not found, we look at tokens that are within an edit distance of num_typos characters from the query tokens. Documents that contain the tokens in the query exactly are ranked higher than those containing tokens with larger edit distances.
  3. Proximity: Whether the query tokens appear verbatim or interspersed with other tokens in the field. Documents in which the query tokens appear right next to each other will be ranked above documents where the query tokens exist but are far apart in a text field.
  4. Ordering of query_by fields: A document that matches on a field earlier in the list of query_by fields is considered more relevant than a document matched on a field later in the list.

Based on the above metrics, Typesense calculates a _text_match score for ranking the documents on text relevance.

However, there will be cases when many documents contain the exact tokens in a search query. In such a case, their _text_match will also be the same. That's when user-defined indexed numerical fields can be used to break the tie. You can specify upto two such numerical fields.

For example, let's say that we're searching for books with a query like short story. If there are multiple books containing these exact words, then all those documents would have the same text match score.

To break the tie, we could specify upto two additional sort_by fields. For instance, we could say:

sort_by=_text_match:desc,average_rating:desc,publication_year:desc

This would sort the results in the following manner:

  1. All matching records are sorted by their text match score.
  2. If any two document share the same text match score, sort them by average rating.
  3. If there is still a tie, sort them by their year of publication.
Default ranking order

When you don't provide a sort_by parameter to your search request, the documents will be ranked on the text match score and default sorting field values:

sort_by=_match_score:desc,default_sorting_field:desc

Strict ordering of results on a numerical field

If you wish to sort the documents strictly by an indexed numerical field like price, you can just move the text match score criteria after the price field as follows:

sort_by=price:desc,_text_match:desc

High Availability

You can run a cluster of Typesense nodes for high availability. Typesense uses the Raft consensus algorithm to manage the cluster and recover from node failures.

Since Raft requires a quorum of nodes for consensus, you need to run a minimum of 3 nodes to tolerate a 1-node failure. Running a 5-node cluster will tolerate failures of upto 2 nodes, but at the expense of higher write latencies.

Therefore, we recommend running a 3-node Typesense cluster.

Configuring a Typesense cluster

To start a Typesense node as part of a cluster, use the --nodes argument to point to a file that contains a comma separated string of all nodes in the cluster.

Each node definition should be in the following format:

<ip_address>:<peering_port>:<api_port>

Example content of a --nodes file for a 3-node cluster:

192.168.12.1:8107:8108,192.168.12.2:8107:8108,192.168.12.3:8107:8108

In the example above, the peering port (i.e. the port used for cluster operations) is 8107 and the API port (the actual port to which clients connect to) is 8108.

Client configuration

Typesense clients allow you to specify one or more nodes during client initialization.

Client libraries will load balance reads and writes across all nodes and will automatically strive to recover from transient failures through built-in retries.

Here's a sample 3-node client configuration:

require 'typesense'

client = Typesense::Client.new(
  nodes: [
    {
      host:     '192.168.0.50',
      port:     443,
      protocol: 'https'
    },
    {
      host:     '192.168.0.51',
      port:     443,
      protocol: 'https'
    },
    {
      host:     '192.168.0.52',
      port:     443,
      protocol: 'https'
    }
  ],
  api_key:  '<API_KEY>',
  connection_timeout_seconds: 2
)
import typesense

client = typesense.Client({
  'nodes': [
    {
      host:     '192.168.0.50',
      port:     443,
      protocol: 'https'
    },
    {
      host:     '192.168.0.51',
      port:     443,
      protocol: 'https'
    },
    {
      host:     '192.168.0.52',
      port:     443,
      protocol: 'https'
    }
  ],
  'api_key': '<API_KEY>',
  'connection_timeout_seconds': 2
})
let client = new Typesense.Client({
  'nodes': [
    {
      host:     '192.168.0.50',
      port:     443,
      protocol: 'https'
    },
    {
      host:     '192.168.0.51',
      port:     443,
      protocol: 'https'
    },
    {
      host:     '192.168.0.52',
      port:     443,
      protocol: 'https'
    }
  ],
  'apiKey': '<API_KEY>',
  'connectionTimeoutSeconds': 2
})