Cerial
Decorators

@index

The @index decorator creates a non-unique database index for query performance optimization.

Creates a non-unique index on the field in SurrealDB. This improves query performance for fields that are frequently filtered or sorted, without enforcing uniqueness.

Syntax

model Product {
  id Record @id
  name String @index
  category String @index
  price Float
}

Behavior

  • The index speeds up lookups but does not prevent duplicate values.
  • @index alone does not satisfy the unique field requirement for findUnique, updateUnique, or deleteUnique — those methods require at least one @unique or @id field in the where clause.

@index vs @unique

Aspect@index@unique
Duplicate valuesAllowedRejected by DB
Unique lookupsNot availablefindUnique, updateUnique, deleteUnique
Use casePerformance optimizationData integrity constraint

Example

model Article {
  id Record @id
  title String
  category String @index
  author String @index
  publishedAt Date @createdAt
}
// Both queries benefit from the index
const articles = await client.db.Article.findMany({
  where: { category: 'tech' },
});

const byAuthor = await client.db.Article.findMany({
  where: { author: 'Alice' },
  orderBy: { publishedAt: 'desc' },
});

Null and Optional Fields

Since @index does not enforce uniqueness, null/NONE values have no special behavior — multiple records with the same value (including null) are always allowed.

Array Fields

@index can be applied to array fields. SurrealDB indexes each element individually, which speeds up CONTAINS-style queries:

model Article {
  id Record @id
  tags String[] @index
}
// Per-element index speeds up CONTAINS lookups
const tagged = await client.db.Article.findMany({
  where: { tags: { contains: 'typescript' } },
});

@unique is not allowed on array fields, but @index is — making it the go-to choice for indexing array elements.

Object Fields

@index can be applied to fields within object definitions. Each embedding of the object in a model generates its own independent index using dot-notation paths:

object LocationInfo {
  address String
  country String @index
}

model Store {
  id Record @id
  location LocationInfo
  warehouse LocationInfo?
}

This generates two separate indexes:

  • store_location_country_index on location.country
  • store_warehouse_country_index on warehouse.country

Allowed On

ConstructAllowed
Model fields✅ (any storable type, including arrays)
Object sub-fields
Tuple elements
Relation fields

Restrictions

  • Mutually exclusive with @unique — A field can have @index or @unique, but not both. Use @unique when you need both indexing and a uniqueness constraint.
  • Not on Relation fields — Relation fields are virtual (not stored), so they cannot be indexed.
  • Not on tuple elements — Tuple elements don't support indexing.

On this page