npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@byline/search-postgres

v4.2.0

Published

Byline CMS built-in Postgres full-text search provider

Readme

@byline/search-postgres

The built-in Postgres full-text SearchProvider for Byline CMS. Implements the SearchProvider seam from @byline/core over a weighted tsvector index — ranked search with zero new infrastructure, reusing your existing Postgres connection.

It consumes the type-enriched SearchDocument that core assembles (buildSearchDocument) and stores one weighted row per (collection_path, document_id, locale): title → weight class A, body fields → AD by their declared boost, facet termsC (folded into the searchable vector), with facet ids and filterable scalars kept as jsonb for aggregation / filtering.

See docs/05-reading-and-delivery/07-search.md for the full subsystem design.

Install

pnpm add @byline/search-postgres

pg is a peer dependency — you already have it via @byline/db-postgres.

Register

The provider reuses the host's existing pool (db.pool from pgAdapter), so the index lives in the same database with no second connection:

import { pgAdapter } from '@byline/db-postgres'
import { postgresSearch } from '@byline/search-postgres'
import { defineServerConfig } from '@byline/core'

const db = pgAdapter({ connectionString, collections, defaultContentLocale })

defineServerConfig({
  db,
  search: postgresSearch({ pool: db.pool }),
  // …
})

A collection opts into indexing through its search config ({ body, facets, filters, zones }); initBylineCore() fails fast if a collection opts in but no provider is registered.

Schema & migrations

This driver owns its schema. It is not part of your app's Drizzle migration stream — it ships its own numbered SQL files in migrations/ and tracks what it has applied in its own byline_search_migrations table. There are three ways to apply them; pick per environment.

1. Run the SQL by hand (locked-down / managed Postgres)

The numbered files are the source of truth and are DBA-reviewable:

psql "$DATABASE_URL" -f node_modules/@byline/search-postgres/migrations/0001_init.sql

2. Call migrate() deliberately (recommended for production)

import { migrate } from '@byline/search-postgres'

const { applied } = await migrate(db.pool, { log: (m) => logger.info(m) })
// applied: [1]  (empty when already up to date)

Run it as a deploy/release step, before the app serves traffic. Idempotent and transactional per file.

3. autoMigrate at boot (development convenience)

search: postgresSearch({ pool: db.pool, autoMigrate: true })

Ensures pending migrations at construction. Handy in dev; in production prefer option 2 so startup is deterministic and DDL permissions are explicit.

Capabilities

provider.capabilities
// { facets: false, typoTolerance: false, semantic: false,
//   bm25: false, weighting: true, highlights: true }

The tsvector + ts_rank floor: per-field weighting and highlighting (ts_headline) are supported today. Facet data is indexed, but facet aggregation queries, structured where filtering, fuzzy matching (pg_trgm), BM25 ranking, and semantic/vector retrieval are follow-ups — surfaced honestly through the capability flags so consumers light up only what's available.

Language / locale

Search is per-locale. Each document's text is indexed with the Postgres regconfig mapped from its content locale (enenglish, frfrench, …), falling back to simple (unstemmed) for unmapped locales. Pass locale to search() so the query uses the matching regconfig (a locale-less query falls back to simple and won't match locale-stemmed vectors) — or set defaultLocale so locale-less queries use your default content locale:

postgresSearch({
  pool: db.pool,
  defaultLocale: 'en',             // regconfig for searches that omit `locale`
  localeRegconfig: { th: 'thai' }, // a custom dictionary you've installed
  fallbackRegconfig: 'simple',
})