CLI tool
TryGhost/algolia avatar
TryGhost/algolia

TryGhost/algolia: indexing Ghost posts in Algolia from the CLI and from Netlify Functions

JavaScript CLI and Netlify Functions for indexing Ghost posts in Algolia

22 stars19 forksTypeScriptMIT

At a glance

What is it?
A pnpm monorepo of five TypeScript packages that turn Ghost posts into Algolia records. The CLI suits a one-off backfill; the Netlify Functions suit incremental webhook updates, provided you deal with the authentication gap the README itself flags.
Who is it for?
Adopt it if you run Ghost and Algolia and want the record-shaping logic maintained in one place instead of a script you own. Do not adopt the Netlify Functions as shipped unless you can restrict access to them outside the handlers, because the README states the handlers do not enforce authentication when the key query parameter is omitted.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap between a Ghost site and an Algolia index

Ghost ships its own search, and it is good enough for a blog with a few hundred posts. It stops being good enough when you want typo tolerance, faceting by tag or author, or search that runs on the client without hitting your Ghost instance. Algolia gives you all of that, but it does not know what a Ghost post is. It wants records: a JSON object with an objectID, the fields you want to search, and whatever you want to filter on. Something has to sit between the two and decide how a post becomes a record, how much HTML survives, and what happens when a post is edited or deleted.

That middle layer is what this repository is. It is not an Algolia client wrapper and it is not a Ghost theme component. It is the mapping and the synchronisation, split into five packages so that the batch path and the incremental path share the same record-shaping code. The audience is narrow: a developer running a self-hosted or Ghost(Pro) site who has already decided to pay for Algolia and now has to keep the index honest.

Five packages, two entry points, one record format

The monorepo splits the work by responsibility. @tryghost/algolia-html-extractor takes rendered Ghost HTML and pulls out ordered text fragments. @tryghost/algolia-fragmenter sits on top of that and converts a post into Algolia records, splitting the HTML by heading so that a long article becomes several searchable chunks rather than one blob. @tryghost/algolia-indexer owns the Algolia side: index settings, writing records, deleting them. The two remaining packages are the entry points. @tryghost/algolia is the CLI for the initial index of a site's published posts. @tryghost/algolia-netlify is a set of Netlify Functions that receive Ghost post webhooks and apply the same transformation incrementally.

The split matters because the two paths have genuinely different failure modes. A batch index runs once and either completes or does not. A webhook handler runs on every publish, edit and delete, forever, and has to be idempotent and fast. Putting the fragmenter and the indexer in their own packages means both paths call the same code, so a post indexed by the CLI and the same post indexed by a webhook should produce the same records. That is the design argument for the monorepo layout, and it is a reasonable one.

One detail in the README is worth reading twice: the CLI supports Ghost 6 by requesting up to 100 posts at a time and following Ghost's pagination metadata until every post has been fetched. Pagination is where a backfill silently loses posts, and the README treats it as a headline feature rather than a footnote.

Installing the monorepo and running the first batch index

The repository is private at the root and published per package, so the development path is the one the README documents. Use the Node version declared in .nvmrc. The root package.json sets engines to node >=24, so anything older will not satisfy the manifest. Dependencies are managed with pnpm, and the declared package manager is [email protected].

bash
pnpm install

That installs the monorepo dependencies and links the workspaces. To confirm the checkout is healthy before you point it at a real Algolia application, run the test suite, which also runs lint checks as a posttest step.

bash
pnpm test

The README states that installation, configuration and command options for the batch indexer live in the @tryghost/algolia package guide rather than at the root, so the actual flags and environment variables are not reproduced here. Read packages/algolia/README.md before running the CLI. What the root README does tell you is the shape of the job: the CLI is for the initial index of a site's published posts, not for ongoing updates. If you run it twice, you are relying on the indexer package's behaviour rather than on a documented re-run contract.

For the incremental path, deployment, Algolia configuration and Ghost webhook setup are described in the @tryghost/algolia-netlify guide. The root README adds one deployment fact that is easy to miss: the Netlify deployment publishes only a static landing page alongside the functions, and the repository package and function files are not site assets.

The authentication gap the README warns about

This is the part of the project that deserves the most attention, because the README puts it in a warning block rather than burying it. The current handlers do not enforce authentication when the key query parameter is omitted. A public function URL is not a secret. The README's instruction is direct: do not expose these functions publicly until authentication is enforced or access is restricted outside the handlers.

Read that carefully, because the phrasing leaves a door open. The handlers check a key when one is supplied, but omitting the parameter is not rejected. So the protection is only as good as your ability to prevent anyone from reaching the endpoint without the parameter, which in practice means a Netlify access control layer, a proxy, or a network restriction in front of the function. If your deployment model is a public Netlify site with functions at a guessable path, the shipped code is the wrong tool until that changes. This is not a subtle bug you can configure around inside the handler; it is a design gap the maintainers have documented rather than fixed.

The second limitation is scope. Nothing in the README describes a reconciliation pass that compares the Ghost post list against the Algolia index and repairs drift. The CLI does the initial batch, the functions handle webhooks. If a webhook is missed while your function is down, or if a post is deleted while Netlify is redeploying, the index keeps the stale record until you notice. For a small blog that is survivable. For a site where search results are a product surface, you want a periodic re-run of the batch index or your own diff job, and neither is documented here.

Where this sits next to the alternatives

The obvious alternative is not another Ghost-to-Algolia tool, because there is not much competition in that specific niche. It is Algolia's own indexing clients and the Ghost Content API. Algolia publishes API clients in several languages, and a Ghost site exposes a Content API you can page through. Writing a script that pulls posts from the Content API and pushes records through the Algolia client is perhaps a hundred lines, and you own every line of it.

The difference in approach is where the complexity lives. With this repository, the hard parts are already decided for you: how HTML becomes fragments, how a post splits by heading, how index settings are managed, how deletions are handled. You get a package to upgrade and a record format you did not design. With a hand-rolled script, you choose the record shape, which is an advantage if your search UI needs fields this project does not emit, and a disadvantage the first time you have to write HTML-to-text extraction that handles nested markup without dropping code blocks.

The second alternative is to skip Algolia and keep Ghost's built-in search. That is not a like-for-like swap, but it is the honest comparison for a site with a few hundred posts and no faceting requirement. Algolia's pricing is a recurring cost, and the README gives no guidance on record counts or index size, so the decision rests on your own traffic and post volume rather than on anything in this repository.

Maintenance, publishing and what the MIT licence covers

The README opens with a note that maintenance of this repository has resumed, and that the CLI supports Ghost 6 through paginated requests of up to 100 posts. That is the clearest statement of project health available here; there are no release notes to date a version. If you are evaluating this for production, treat the resumed-maintenance note as the signal and check the repository's own commit history for how recent that resumption is, because the README does not date it.

Upgrade cost is shaped by the release process. The repository uses Nx to version packages independently, and routine releases run through root aliases: pnpm ship:patch, pnpm ship:minor, pnpm ship:major. Releasing a single package goes through pnpm ship with an Nx project name, and the README shows a dry run first with --projects=@tryghost/algolia --dry-run. The ship command runs the test suite, updates the selected versions and their internal dependants, creates the release commit and tags, then pushes them upstream. The Publish workflow handles npm trusted publishing, and the README is explicit that you should never run npm publish by hand. For a consumer of these packages, independent versioning means @tryghost/algolia and @tryghost/algolia-indexer can drift apart, so pin versions rather than floating them if you depend on more than one package directly.

Licensing is straightforward: MIT, copyright Ghost Foundation, from 2013 through 2026. MIT permits commercial use and modification, and the usual obligation is preserving the copyright notice and permission notice. Separately, the README notes that Ghost and the Ghost Logo are trademarks of Ghost Foundation Ltd, with a trademark policy linked from the repository. That is a naming concern rather than a code concern, and it is worth checking if you plan to describe your product as a Ghost product. This is not legal advice; read the LICENSE file and the trademark policy yourself.

Editorial conclusion

Adopt it if you run Ghost and Algolia and want the record-shaping logic maintained in one place instead of a script you own. Do not adopt the Netlify Functions as shipped unless you can restrict access to them outside the handlers, because the README states the handlers do not enforce authentication when the key query parameter is omitted. Verify two things first: that your Node version satisfies the engines field of >=24, and that the CLI's pagination against your Ghost version returns every post before you trust the index.

Frequently asked questions

What is TryGhost/algolia used for?

It turns Ghost posts into Algolia records and keeps the index up to date. The CLI handles the initial index of a site's published posts, and the Netlify Functions process Ghost post webhooks to update the index incrementally.

How do I install TryGhost/algolia?

Use the Node version declared in .nvmrc and run pnpm install at the repository root to install the monorepo dependencies and link the workspaces. Installation, configuration and command options for the CLI are documented in the @tryghost/algolia package guide rather than at the root.

Does the Netlify Functions deployment enforce authentication?

The README warns that the current handlers do not enforce authentication when the key query parameter is omitted, and states that a public function URL is not a secret. It advises not exposing the functions publicly until authentication is enforced or access is restricted outside the handlers.

Which Ghost versions does the CLI support?

The README states the CLI supports Ghost 6 by requesting up to 100 posts at a time and following Ghost's pagination metadata until every post has been fetched. No other version support is documented.

What licence does TryGhost/algolia use?

MIT, copyright Ghost Foundation, covering 2013 through 2026. The README separately notes that Ghost and the Ghost Logo are trademarks of Ghost Foundation Ltd and links a trademark policy.

Official sources

  1. Official README
  2. Project repository