Menu

Search

Full-text search over your content, powered by SQLite FTS5 — no external search service, nothing to install. Point it at a folder and start querying.

Basil-only. @SEARCH requires the Basil server environment.

Quick Start

let {search, error} = @SEARCH({watch: @./docs})

let q = @params.q ?? ""
let results = search.query(q, {limit: 10})

<form method="get">
    <input type="search" name="q" value={q} placeholder="Search…"/>
</form>

<ul>
    for (result in results.items) {
        <li>
            <a href={`/{result.path}`}>result.title</a>
            <p>result.snippet</p>
        </li>
    }
</ul>

On the first query, Basil scans the watched folder, reads titles, tags, and dates from YAML frontmatter, extracts headings for ranking, and builds the index. Every query after that checks the folder for changes, so new, edited, and deleted files show up on their own.

@SEARCH(options)

Returns {search, error} — the search instance, or an error message if setup failed.

Key Type Description
path string SQLite index file (":memory:" for tests)
watch path or array Folder(s) to index automatically
snippetLength int Approximate snippet length in characters (default 200, max ~320)
highlightTag string HTML tag wrapped around matched terms (default "mark")

Indexes Markdown and HTML out of the box, plus text-based PDF and DOCX files (50 MB per-file limit). Unrecognised option keys are an error, so typos don't fall back to silent defaults. See the search guide for extensions, weights, and tokenizer.

search.query(text, options?)

Key Type Default Description
limit int 10 Maximum results
offset int 0 Pagination offset
raw bool false Pass the query straight to FTS5 (advanced)
filters dictionary Narrow results by tag or date (see below)

The query syntax works like a search engine: words are ANDed together, "quotes make phrases", and a -minus excludes a word. An empty query returns empty results, so it's safe to wire straight to a form.

Returns {items, total, limit, offset, query}, where total reflects the filtered match count. Each item has:

Field Description
url Link to the result — use this for documents added with search.add(), which have no source path
path Path object for the source file — build links with `/{result.path}` (omitted for manually added documents)
title Document title (frontmatter, first heading, or filename)
snippet Excerpt with matched terms wrapped in <mark>…</mark> (or your highlightTag)
rank 1-based position in the results
score Relevance score, mostly useful for debugging
date The document's date, when it has one

Filters

let results = search.query(@params.q, {
    filters: {
        tags: ["tutorial", "guide"],  // Match any of these tags
        dateAfter: @2024-01-01,       // On or after this date (inclusive)
        dateBefore: @2024-12-31       // On or before this date (inclusive)
    }
})
Key Type Description
tags array or string Keep documents carrying any of the listed tags
dateAfter date or string Keep documents dated on or after this point
dateBefore date or string Keep documents dated on or before this point

Dates accept Parsley datetime literals (@2024-01-01) or ISO strings ("2024-01-01"). Bounds are inclusive and compared in UTC. Documents without a date are excluded whenever a date filter is set.

Beyond Watched Folders

The instance has a few more methods, all covered in the guide:

  • add, update, remove — index things that aren't files: database rows, API responses, generated pages
  • stats() — document count, index size, last indexed time
  • reindex() — drop everything and rebuild from the watched folders

When to Use It

Good for documentation sites, blogs, wikis, and apps up to roughly 100k documents — anything where "just works, zero config" beats search-cluster features. If you need typo tolerance, multi-language stemming, or millions of documents, reach for Meilisearch or Elasticsearch instead.

See Also

  • The Search Guide — how indexing works file type by file type, ranking and tuning, query syntax, manual indexing, and troubleshooting
  • Routing@params and friends