@b3nab/payload-hypervalue

The history layer for Payload CMS

Add custom: { hypervalue: true } to a field or collection, every change gets stored in a TimescaleDB hypertable. Query full history, a point in time, or a range.

products2025-06-15
pricenumber$45.50
titletextWidget Pro
statusselectpublished
products2025-06-14
pricenumber$44.99
titletextWidget Pro
statusselectdraft
products2025-06-13
pricenumber$39.99
titletextWidget
statusselectdraft
products2025-06-12
pricenumber$42.99
titletextWidget
statusselectdraft
products2025-06-11
pricenumber$41.00
titletextWidget
statusselectdraft

Full history, not just the latest value

Your fields and collections still behave like normal Payload. The ones you track with hypervalue also record every change with a timestamp. Query their history by point-in-time, range, or get the full timeline.

products.price
Jun 12
$42.99
Jun 13
$39.99
Jun 14
$44.99
Jun 15
$45.50
products.priceJun 12–15
$42.99Jun 12$39.99Jun 13$44.99Jun 14$45.50Jun 15

Hypertables

Track entire collections as wide tables or individual fields as narrow tables. Configurable chunk intervals, compression, and retention.

Access control

Queries respect Payload's collection-level access control. Override with overrideAccess when you need to.

Cascade deletes

Delete a document and its history goes with it. Foreign key constraints handle the cleanup.

Draft awareness

Optionally track draft saves. Off by default so only published changes are recorded.

Type-safe queries

payload.hypervalue() is fully typed. Module augmentation adds it to the Payload instance automatically.

All-in-one DB image

PostgreSQL 17 + PostGIS + pgvector + TimescaleDB. One docker pull, zero extension fiddling.

Query history from anywhere

Get the full timeline, look up a value at a specific moment, or pull a range. Works over REST with the same access control your collections already have, or server-side with a typed API.

REST API
Full history
GET /api/hypervalue/products/:id/price
Point in time
GET ...?at=2025-06-01T00:00:00Z
Range
GET ...?from=2025-01-01&to=2025-06-01
Local API
Server-side
const history = await payload.hypervalue({
  collection: 'products',
  id: doc.id,
  field: 'price',
  from: new Date('2025-01-01'),
  to: new Date('2025-06-01'),
})
$ pnpm add @b3nab/payload-hypervalue