Getting started

Getting started

Install Narsil, create your first index, insert documents, and run a ranked full-text query in a few minutes.

Table of Contents

Narsil runs inside your process, with no server to provision. For your first search, install the package, create an index with a typed schema, insert documents, and query.

Install the package

pnpm add -E @delali/narsil

The package includes TypeScript types and runs in Node.js, the browser, and web workers from the same import.

Create an engine and an index

Every index declares a schema up front. The schema determines type checking on inserts, which fields are filterable, and how each field is tokenised.

search.ts
import { createNarsil } from '@delali/narsil'
 
const narsil = await createNarsil()
 
await narsil.createIndex('products', {
  schema: {
    title: 'string',
    description: 'string',
    price: 'number',
    inStock: 'boolean',
    category: 'enum',
    tags: 'string[]',
  },
  language: 'english',
})

Field types cover string, number, boolean, enum, and geopoint, the array variants such as string[], number[], boolean[], and enum[], and vector[N] for embeddings. The language option selects the analyser used for tokenising and stemming text fields.

Insert documents

Insert documents one at a time, or in batches when you are loading a corpus. With the index in place, add an insert call to search.ts; the green lines mark what you are adding.

search.ts
import { createNarsil } from '@delali/narsil'
 
const narsil = await createNarsil()
 
await narsil.createIndex('products', {
  schema: {
    title: 'string',
    description: 'string',
    price: 'number',
    inStock: 'boolean',
    category: 'enum',
    tags: 'string[]',
  },
  language: 'english',
})
 
await narsil.insert('products', { 
  id: 'mech-keyboard',
  title: 'Mechanical Keyboard',
  description: 'Cherry MX Brown switches with PBT keycaps and USB-C connection',
  price: 129.99,
  inStock: true,
  category: 'electronics',
  tags: ['peripherals', 'typing', 'mechanical'],
})

insertBatch accepts an array of documents and reports per-document failures without abandoning the rest of the batch.

Query with ranking, filters, and highlighting

Queries combine a search term with filters, per-field boosts, highlighting, and a result limit. Add the query to the end of search.ts and read the ranked hits; results come back ranked by BM25.

search.ts
import { createNarsil } from '@delali/narsil'
 
const narsil = await createNarsil()
 
await narsil.createIndex('products', {
  schema: {
    title: 'string',
    description: 'string',
    price: 'number',
    inStock: 'boolean',
    category: 'enum',
    tags: 'string[]',
  },
  language: 'english',
})
 
await narsil.insert('products', {
  id: 'mech-keyboard',
  title: 'Mechanical Keyboard',
  description: 'Cherry MX Brown switches with PBT keycaps and USB-C connection',
  price: 129.99,
  inStock: true,
  category: 'electronics',
  tags: ['peripherals', 'typing', 'mechanical'],
})
 
const results = await narsil.query('products', { 
  term: 'mechanical keyboard',
  filters: {
    fields: {
      inStock: { eq: true },
      price: { lte: 200 },
    },
  },
  boost: { title: 3.0, description: 1.5 },
  highlight: {
    fields: ['title', 'description'],
    preTag: '<mark>',
    postTag: '</mark>',
  },
  limit: 10,
})
 
console.log(JSON.stringify(results, (k, v) => (typeof v === 'number' ? Number(v.toFixed(2)) : v), 2))

Each hit carries the stored document, its BM25 relevance score, and a highlights map for the fields you asked to highlight. The title came back wrapped in <mark> tags at the matched positions, so hit.highlights.title.snippet reads <mark>Mechanical</mark> <mark>Keyboard</mark>, ready to render. The description holds no query terms, so its positions array is empty. The title boost of 3.0 lifts the score, and the one keyboard comes back because it passed both filters.

The search box on this site runs on Narsil. The engine indexes every page at build time and answers queries through a small API route.

Where to go next

  • The Narsil README documents every feature area, including vector search, hybrid ranking, geosearch, persistence adapters, partitions, and the HTTP server.
  • The benchmarks page shows how Narsil ranks and performs against production search engines on BEIR datasets.
  • The changelog lists what each release added.