Collections

A collection is a group of documents sharing the same schema. Each collection has typed fields, independent indexes, and configurable options for search, filtering, and sorting.

Create a Collection

POST /collections
Content-Type: application/json
X-TYPESENSE-API-KEY: YOUR_API_KEY

{
  "name": "products",
  "fields": [
    {"name": "title", "type": "string"},
    {"name": "description", "type": "string"},
    {"name": "price", "type": "float", "sort": true},
    {"name": "category", "type": "string", "facet": true},
    {"name": "tags", "type": "string[]", "facet": true},
    {"name": "in_stock", "type": "bool"},
    {"name": "rating", "type": "int32", "sort": true}
  ],
  "default_sorting_field": "price"
}

Field Types

TypeDescriptionFilterableSortableSearchable
stringFull-text searchable textYes (exact match)NoYes
string[]Array of stringsYesNoYes
int3232-bit signed integerYesYesNo
int6464-bit signed integerYesYesNo
float64-bit floating pointYesYesNo
boolBoolean true/falseYesNoNo
int32[]Array of 32-bit integersYesNoNo
int64[]Array of 64-bit integersYesNoNo
geopointLatitude/longitude coordinateYes (geo radius)No *No
float[]Vector embedding (with num_dim)NoNoYes (vector)

* Geopoint fields cannot be used as default_sorting_field or with the sort option, but you can sort by geo distance using the sort_by=location(lat,lng):asc syntax in queries.

Field Options

OptionTypeDefaultDescription
facetboolfalseInclude this field in facet_by results
indexbooltrueIndex this field for search and filtering
optionalboolfalseAllow documents without this field
sortboolfalseEnable sort_by on this field (numeric and geopoint types)
stembooltrueApply language stemming to this text field
localestringLanguage override for this field (see Languages for codes)
num_dimintVector dimensions (required for float[] vector fields)
vec_diststringcosineVector distance metric: cosine, ip (dot product), l2 (Euclidean)

Schema Options

OptionTypeDefaultDescription
default_sorting_fieldstringDefault field for sort_by when not specified in queries
enable_nested_fieldsboolfalseEnable dotted field names for nested objects
default_languagestringenDefault stemming language (see Languages for codes)
symbols_to_indexstring[][]Special characters to include in the index (e.g., ["+", "#"])
token_separatorsstring[][]Additional characters to split tokens on
persistence_enabledbooltruePersist this collection to disk
index_modestringbatchIngest mode: batch (rebuild index on commit) or realtime (instant updates)

Index Modes

Torque has two index modes, set per collection via index_mode in the schema. This is a key architectural difference from Typesense, which always updates documents in place.

ModeHow It WorksBest For
Batch (default) Documents are streamed in, then the full index is rebuilt atomically on commit. The old index serves queries until the new one is ready (zero downtime). Periodic bulk loads, full refreshes, initial imports, ETL pipelines
Realtime Each upsert or delete is immediately visible via a lightweight overlay. The overlay is merged into the base index during compaction. Live database sync, continuous streaming, low-latency updates

Batch Mode

Batch mode is the default and produces the most compact, optimized indexes. The workflow is:

  1. Client opens a TCP session and sends all documents in batches
  2. Client sends a Commit message
  3. Torque rebuilds the entire index in the background (inverted index, filters, sort arrays, HNSW graph)
  4. The new index is swapped in atomically — queries are never blocked

Create a batch-mode collection (this is the default):

{
  "name": "products",
  "fields": [
    {"name": "title", "type": "string"},
    {"name": "price", "type": "float", "sort": true}
  ]
}

Note: Each commit rebuilds the full index. Batch mode is ideal when you can batch all changes together (e.g., nightly refreshes, periodic syncs). For continuous updates, use realtime mode.

Realtime Mode

Realtime mode makes documents searchable immediately after upsert, without waiting for a full index rebuild. Torque achieves this with an overlay — a lightweight in-memory layer that stores recent mutations and is merged with the base index at query time.

  1. Client sends an Upsert message — the document is added to the overlay
  2. Searches merge results from the base index and the overlay transparently
  3. Compaction periodically consolidates the overlay into a new base index

Create a realtime-mode collection:

{
  "name": "products_live",
  "index_mode": "realtime",
  "fields": [
    {"name": "title", "type": "string"},
    {"name": "price", "type": "float", "sort": true}
  ]
}

Overlay & Compaction

The realtime overlay is persisted to disk (via redb) with a sub-second flush interval, so mutations survive restarts. As the overlay grows, search performance may degrade slightly because the overlay is scanned linearly. Compaction rebuilds the base index to absorb the overlay:

  • Automatic: Runs on a timer (--compaction-interval-secs, default 30 min) or when memory pressure exceeds the threshold (--compaction-memory-threshold-percent)
  • Manual: POST /collections/{name}/documents/compact
  • Suspend/Resume: Pause ingestion during maintenance with POST /collections/{name}/suspend and POST /collections/{name}/resume

Choosing a Mode

BatchRealtime
Update visibilityAfter commit (seconds to minutes)Immediate (sub-millisecond)
Index qualityFully optimized (best query performance)Base + overlay (slightly higher latency until compaction)
Disk writesOne write per commitContinuous overlay flush (sub-second interval)
DeletesRemove documents by not including them in the next batchInstant delete via overlay tombstones
Typesense equivalentNo equivalent (Typesense always updates in place)Similar to Typesense default behavior

Tip: You can use both modes in the same Torque instance. For example, keep a frequently-updated collection in realtime mode while keeping a large reference dataset in batch mode for optimal query speed.

Nested Fields

Enable nested fields to use dotted field names that map to nested JSON objects:

{
  "name": "companies",
  "enable_nested_fields": true,
  "fields": [
    {"name": "name", "type": "string"},
    {"name": "address.city", "type": "string", "facet": true},
    {"name": "address.country", "type": "string", "facet": true},
    {"name": "financials.revenue", "type": "float", "sort": true}
  ]
}

Documents can then be imported with nested JSON, which Torque automatically flattens to match the field names:

{
  "name": "Acme Corp",
  "address": {"city": "Stockholm", "country": "Sweden"},
  "financials": {"revenue": 1500000.0}
}

Nested fields also support element-level AND filtering. See Filtering for details.

Languages

Torque supports Snowball stemming for 17 languages. Set the language per field using locale or per collection using default_language:

CodeLanguage
enEnglish (default)
deGerman
frFrench
esSpanish
ptPortuguese
itItalian
nlDutch
svSwedish
noNorwegian
daDanish
fiFinnish
ruRussian
arArabic
elGreek
huHungarian
roRomanian
trTurkish

Update Schema

Add or remove fields from an existing collection without deleting it:

PATCH /collections/products
Content-Type: application/json
X-TYPESENSE-API-KEY: YOUR_API_KEY

{
  "fields": [
    {"name": "brand", "type": "string", "facet": true},
    {"name": "old_field", "drop": true}
  ]
}

Adding a new field builds the index for that field. Setting "drop": true removes the field and its index data.

List Collections

GET /collections
X-TYPESENSE-API-KEY: YOUR_API_KEY

Returns all collections with their schemas, document counts, and creation timestamps.

Get Collection

GET /collections/products
X-TYPESENSE-API-KEY: YOUR_API_KEY

Delete Collection

DELETE /collections/products
X-TYPESENSE-API-KEY: YOUR_API_KEY

Collection Aliases

Aliases are logical names that point to a collection. Use them for zero-downtime schema migrations:

# Create an alias
PUT /aliases/products
Content-Type: application/json
X-TYPESENSE-API-KEY: YOUR_API_KEY

{"collection_name": "products_v2"}

Queries to the alias name are transparently routed to the target collection. To migrate, create a new collection, index your data, then update the alias:

# Switch the alias to the new collection
PUT /aliases/products
{"collection_name": "products_v3"}
# List all aliases
GET /aliases

# Get a specific alias
GET /aliases/products

# Delete an alias
DELETE /aliases/products