> Complete content index: https://narsil.sondelali.com/llms.txt

# Getting started

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

URL: https://narsil.sondelali.com/docs/getting-started
Section: Getting started
Version: 0.2 (@delali/narsil@0.2.2, latest)

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

```bash pm
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.

```ts title="search.ts"

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 <Tooltip tip="An embedding is a list of numbers a machine learning model produces to represent the meaning of a piece of text. Texts with similar meanings get numerically close embeddings.">embeddings</Tooltip>. The `language` option selects the analyser used for tokenising and <Tooltip tip="Stemming reduces each word to its root form, so 'searching' and 'searched' index as the same term and match each other.">stemming</Tooltip> text fields.

## Insert documents

Insert documents one at a time, or in batches when you are loading a <Tooltip tip="A corpus is the full collection of documents a search engine indexes and searches over.">corpus</Tooltip>. With the index in place, add an insert call to `search.ts`; the green lines mark what you are adding.

```ts title="search.ts"

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', { // [!code ++:9]
  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 <Tooltip tip="BM25 is the standard keyword ranking formula. It scores a document higher when the query terms appear often in it, are rare across the whole collection, and appear in shorter fields.">BM25</Tooltip>.

```ts title="search.ts"

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', { // [!code ++:18]
  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))
```

```json result
{
  "hits": [
    {
      "id": "mech-keyboard",
      "score": 2.01,
      "document": {
        "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"
        ]
      },
      "highlights": {
        "title": {
          "snippet": "<mark>Mechanical</mark> <mark>Keyboard</mark>",
          "positions": [
            {
              "start": 0,
              "end": 10
            },
            {
              "start": 11,
              "end": 19
            }
          ]
        },
        "description": {
          "snippet": "Cherry MX Brown switches with PBT keycaps and USB-C connection",
          "positions": []
        }
      }
    }
  ],
  "count": 1,
  "elapsed": 0.21
}
```

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.

<Note>
  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.
</Note>

## Where to go next

- The [Narsil README](https://github.com/assetcorp/narsil#readme) documents every feature area, including vector search, hybrid ranking, geosearch, persistence adapters, partitions, and the HTTP server.
- The [benchmarks](/benchmarks) page shows how Narsil ranks and performs against production search engines on BEIR datasets.
- The [changelog](/changelog) lists what each release added.
