# astro-fuse

> Use Fuse.js to search documents in your Astro site

Latest version **2.0.1** (published 2026-07-05) · MIT license · 0 weekly downloads

## Install

```sh
npm install astro-fuse
pnpm add astro-fuse
yarn add astro-fuse
bun add astro-fuse
```

## Health

**Score 75/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; has provenance; recently updated; high maintenance score; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 2.0.1 |
| Published | 2026-07-05 |
| First published | 2023-03-17 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 5 |
| Unpacked size | 16.6 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Provenance | attested (GitHub Actions) |
| GitHub stars | 11 |
| Author | johnny-mh |
| Maintainers | everedifice |
| Keywords | astro-integration, astro-component |

## Links

- npm: https://www.npmjs.com/package/astro-fuse
- Repository: https://github.com/johnny-mh/devlog
- Homepage: https://github.com/johnny-mh/devlog/tree/main/packages/astro-fuse
- Issues: https://github.com/johnny-mh/devlog/issues
- npm.io page: https://npm.io/package/astro-fuse

## Dependencies (5)

- [cheerio](https://npm.io/package/cheerio.md) 1.0.0-rc.12
- [fuse.js](https://npm.io/package/fuse.js.md) ^7.4.2
- [js-yaml](https://npm.io/package/js-yaml.md) ^4.1.0
- [html-to-text](https://npm.io/package/html-to-text.md) ^9.0.5
- [lodash.debounce](https://npm.io/package/lodash.debounce.md) ^4.0.8

## Recent versions

- 2.0.1 (latest) — 2026-07-05
- 2.0.0 — 2026-06-29
- 1.0.4 — 2025-05-12
- 1.0.3 — 2025-04-24
- 1.0.2 — 2025-04-24
- 1.0.1 — 2024-07-24
- 1.0.0 — 2024-07-24
- 0.0.7 — 2024-04-23
- 0.0.6 — 2023-09-22
- 0.0.5 — 2023-09-21
- 0.0.5-alpha.0 — 2023-08-13
- 0.0.4 — 2023-08-09
- 0.0.3 — 2023-05-05
- 0.0.2 — 2023-03-17
- 0.0.1 — 2023-03-17

## README

# astro-fuse

![The search layer of the johnny-dev blog](./search-layer-demo.gif)

This [Astro integration](https://docs.astro.build/en/guides/integrations-guide/) generates the _fuse.json_ index file of [Fuse.js](https://fusejs.io/) when your Astro project during build.

Use this plugin to add content search functionality to your Astro site.

## Compatibility

| `astro-fuse` | Supported Astro     | Modes                          | Status                                      |
| ------------ | ------------------- | ------------------------------ | ------------------------------------------- |
| `2.x`        | Astro `>=5`         | output only                    | Active (tested on Astro 7)                  |
| `1.x`        | Astro `4` – `5`     | output (`4`–`5`), source (`4`) | Maintenance only                            |

`2.x` requires Astro 5 or later. It adapts to two changes in the Astro 5/6 cycle:

- Astro 5 **deprecated** the `routes` field on the `astro:build:done` hook and Astro 6 **removed** it. `2.x` reads route data from the `astro:routes:resolved` hook (added in Astro 5) instead. This is why `1.x` keeps working through Astro 5 but breaks on Astro 6+ — those users need `2.x`.
- Astro 5's Content Layer no longer routes content files through Vite's `transform` hook, which the old `basedOn: 'source'` mode depended on. **Source mode was removed** in `2.x` (it only ever worked on Astro 4); output mode is the only mode.

On Astro 4 use `astro-fuse@1`. On Astro 5 either line works (`2.x` recommended). On Astro 6+ use `astro-fuse@2`.

## Usage

First, install the `astro-fuse` packages using your package manager.

```sh
npx astro add astro-fuse

pnpm astro add astro-fuse

yarn astro add astro-fuse
```

Then, apply this integration to your `astro.config.*` file using the integrations properly.

```js ins={3} "fuse(['content'])"
// astro.config.mjs
import { defineConfig } from 'astro/config'
import fuse from 'astro-fuse'

export default defineConfig({
  integrations: [fuse(['content'])],
})
```

When you install the integration, you can add search component on a page.

> You need run `astro build` before using it. for detailed explanations, please refer to the [remarks](#remarks) section below.

```astro
<!-- Search.astro -->
<custom-search>
  <input data-search-inp type="text" />
  <ul data-search-result></ul>
</custom-search>

<script>
  import type { OutputBaseSearchable } from 'astro-fuse'

  class CustomSearch extends HTMLElement {
    list = this.querySelector<HTMLUListElement>('[data-search-result]')

    constructor() {
      super()

      this.querySelector<HTMLInputElement>(
        '[data-search-inp]'
      )?.addEventListener('input', this.onInput.bind(this))
    }

    async onInput(e: Event) {
      const { list } = this

      if (!list) {
        return
      }

      // create fuse instance from index
      const { loadFuse } = await import('astro-fuse/client')
      const fuse = await loadFuse()

      const results = fuse.search<OutputBaseSearchable>((e.target as HTMLInputElement).value.trim())

      list.innerHTML = results
        .map(
          ({ item }) =>
            `<li><a href="${item.pathname}">${item.frontmatter.title}</a></li>`
        )
        .join('')
    }
  }

  customElements.define('custom-search', CustomSearch)
</script>
```

You can also just load and use the index file as shown in the example below.

> Since the size of the index file can be large depending on the settings, it is recommended to lazy-load the index file.

```astro
<!-- Search.astro -->
<script>
  import Fuse from 'fuse.js'

  fetch('/fuse.json')
    .then(res => res.json())
    .then(({index, list}) => {
      const fuse = new Fuse(list, undefined, Fuse.parseIndex(index))

      fuse.search('...')
    })
</script>
```

## Methods and Options

### fuse(keys, [options])

#### keys

You can provide the key values of the properties you want to search in addition to the body.

See [Fuse.js keys option](https://www.fusejs.io/api/options.html#keys)

The index is generated from the HTML files produced by your build, so you can
search the static rendering results of components used in your Markdown/MDX
pages.

> **Removed in v2:** the `basedOn: 'source'` mode was removed. It relied on
> Vite transforming content files, which no longer happens with Astro 5's
> Content Layer. Use the default (output) mode.

#### filename

The file name of the index file to be generated.

#### filter

All HTML files generated as a result of the build are subject to search index generation. If you want to restrict this, use the filter option.

```js
// astro.config.mjs
fuse(['content', 'frontmatter.title'], {
  filter: (path) => /^\/post\/[^/]+\/$/.test(path),
})
```

#### extractContentFromHTML

The index is generated from the HTML files produced by the build. This may include unnecessary content such as text in the header area. You can use the extractContentFromHTML option to select the elements that need to be searched.

```js
// astro.config.mjs
// ...
fuse(
  ['content', 'frontmatter.title'],
  {
    extractContentFromHTML: 'article' // index text inner <article> element.
    extractContentFromHTML: $ => $('div#content') // or. you can use cheerio instance.
  }
)
```

#### extractFrontmatterFromHTML

The index is generated from the rendered HTML files, so frontmatter cannot be extracted directly. If frontmatter is required, you can use the extractFrontmatterFromHTML option to make frontmatter searchable as well.

For example, if you need the original title value because the pathname is sluggified, the following MDX file can be bundled into various path HTML files like /content/2023-08-14-a-page-title.mdx => blog/2023/08/a-page-title.html.

```astro
---
title: A Page Title
---
```

In this situation, the `extractFrontmatterFromHTML` option can be helpful. If you render the title to the `meta[property="og:title"]` tag, you can get it with the following options.

```js
// astro.config.mjs

fuse(['content', 'frontmatter.title'], {
  extractFrontmatterFromHTML: ($) => {
    // read that element value. $ is cheerio instance.
    const el = $('[data-frontmatter]')

    if (el.length) {
      return JSON.parse(el.first().val())
    }

    return { title: $('h1').first().text() }
  },
})
```

```astro
<!-- [slug].astro -->
---
const { frontmatter } = Astro.props;
---

<html>
<!-- .. make hidden input for render frontmatter .. -->
<input
    type="hidden"
    data-frontmatter
    value={JSON.stringify(frontmatter)}
/>
</html>
```

The `$` is a Cheerio instance, and you can use it to search for elements. For more information, see the Selecting Elements links. [Selecting Elements](https://cheerio.js.org/docs/basics/selecting)

### loadFuse([options])

#### url

The path to the index file to be used as the first argument of `fetch`.

#### init

A `RequestInit` object containing any custom settings that you want to apply to the request.

See [fetch options](https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch#options)

#### options

The option object used when creating a Fuse.js instance.

See [Fuse.js options](https://www.fusejs.io/api/options.html)

## Example

- [The search layer of the johnny-dev blog](/apps/devlog/src/components/SearchLayer.astro)

## Remarks

- In a development environment, the index file for Fuse.js may not be created immediately when the server starts. In this case, you can request a page that uses a Markdown file to trigger the build process. Please note that the file is created immediately in the production build stage. If it is not created, please report an issue.

---
_Source: https://npm.io/package/astro-fuse · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
