paged.data — database publishing

A catalogue is a database wearing typography

Catalogues, price lists and directories generated from your data: SQL over CSV, JSON, Parquet and Excel in the browser, bound to the layout and kept in sync.

AGPL-3.0 OR PMEL·canary — usable, moving fast·0.1.0-canary.11·github.com/paged-media/plugin-data ↗

42
functions in the binding language
5
file formats, plus remote URLs
4
barcode kinds, drawn as vectors
SQL in the browser

Your data, queried with DuckDB — in the tab

The Data sources panel imports CSV, TSV, JSON (an array or newline-delimited), Parquet and Excel .xlsx — each as a table in DuckDB, running as WebAssembly in your browser. A remote CSV, TSV, JSON or Parquet URL can be added too; it is fetched only from an origin you have consented to.

The Data query panel takes SQL with DuckDB’s own diagnostics, offers filter, sort and group builders that write the SQL for you, and previews the first 50 rows. Every query passes a guard that admits exactly one read-only statement over your sources, and each source has a refresh policy: manual, on open, or every N seconds for a remote one.

The Catalog opener: a forty-eight-row order book, shown as the raw CSV before any engine touches it. The chapter publishes from it rather than decorating with it.
The Catalog opener: a forty-eight-row order book, shown as the raw CSV before any engine touches it. The chapter publishes from it rather than decorating with it.
The binding language

Fields, tables, images, rules — bound to the layout

A binding connects a query to the page through an expression in paged.data’s own binding language: 42 functions, arithmetic, comparison and concatenation, with errors as values. Number, currency, percent and date formats follow a locale — nine are built in, from en and de to fr, it, es and nl — and a field can carry its own.

Bindings write native content: a variable becomes a tagged placeholder field, a table binding a native table, an image binding a placed image, a visibility binding shows or hides an element, and a style rule applies the document’s own paragraph, character or cell styles to the records it fires on — with a preview of which records those are.

The record card: three tagged placeholder fields — customer, product, unit price — each resolved from record 1001 by the engine and placed at the text caret. A data refresh re-resolves them in place.
The record card: three tagged placeholder fields — customer, product, unit price — each resolved from record 1001 by the engine and placed at the text caret. A data refresh re-resolves them in place.
Record flow
Fields per record with optional grouping, paginated into frames on as many pages as the flow needs.
Data Merge
Merges every record into a page of <<field>> frames, single or multiple records per page, matching InDesign on all eight recorded fixtures.
Data sets
Capture the current values or one set per record, apply a set in one undo step, import or export a variable library.
A data provider
Publish a query result for other plugins to read, where the host offers a provider registry.
Barcodes, drawn — and a review before anything changes

Vector barcodes and sync review

EAN-13, UPC-A, Code-128 and QR are encoded by the engine and drawn as one closed vector path per dark module, scaled to their frame — never pixels, so they print at any size.

When the data changes, nothing is overwritten behind your back. Each binding shows its state — synced, stale, pinned, overridden or error — with Pin, Unpin and Accept source. “What changed?” lists the rows added, removed and changed since the document was last written from the data, each changed cell before and after, and which bindings each change reaches. Refresh fields then rewrites only the fields whose value changed, in one undo step.

Four symbologies, one order book: Code-128, EAN-13 and QR drawn as native filled paths from the order book's columns. The UPC-A frame is empty on this run, and the page says so rather than faking a symbol.
Four symbologies, one order book: Code-128, EAN-13 and QR drawn as native filled paths from the order book's columns. The UPC-A frame is empty on this run, and the page says so rather than faking a symbol.
Automation

The same engine, without a browser

paged-data-batchis a command-line build of the same engine. It reads a JSON job — the document’s data session, the query results already materialised, a frame list and a mode — and prints the paginated flow of every output document: one per record, one per group, or one catalogue. A script evaluated in the sandboxed Boa interpreter can supply the locale, the parameters and the build.

Live — paged.data as its own application

The catalogue builder, in this tab

Solo mode boots the real editor as paged.data, with the sources, query and bindings panels in the cockpit. Import a file and query it; DuckDB runs in your browser and your data is not uploaded.

The paged editor booted as paged.data
Needs a browser with WebGPU (Chrome, Edge, Safari 26).open full screen ↗
How it lives in a document

The recipe in the container, the result on the page

Sources, queries, binding definitions, data sets, the locale, pinned decisions and the imported files themselves are saved as this plugin’s session part inside the .paged container. Opening the document restores the session and finds its placed fields again; remote sources come back as inert descriptors and nothing is fetched on open.

What the bindings wrote is ordinary IDML — text, fields, tables, images and vector barcodes — so the IDML InDesign opens shows the published result.

Publish from the data, not decorated with it.

The full list of what ships and what does not is in the repository’s status record ↗.

Spec sheet — from the registry, not from marketing

paged.data features

Plugin · data · 22
Print automation / batch generation (per-record / per-group / one catalog)
data.automation.batch
stable· 4 tests
Barcode / QR symbologies — clean-room EAN-13/UPC-A, Code-128, QR encoders + binding + VECTOR lowering (§9.7)
data.barcode.symbology
stable· 14 tests
Bindings authoring — first-class add-binding flow in the bindings panel
data.bind.authoring
stable· 2 tests
Change-highlighting on refresh — per-binding "what changed since last sync" report (§8)
data.bind.change-report
stable· 2 tests
Binding + synchronization engine — resolution graph, sync states, identity diff
data.bind.engine
stable· 18 tests
Field-mapping wizard — map source columns → variable bindings one-click (§9)
data.bind.field-mapping
stable· 4 tests
Record-preview stepper — resolve a binding against a chosen record index N (§9)
data.bind.preview-step
stable· 3 tests
Illustrator-compatible variable-library XML — import + export (§16.4)
data.dataset.library-xml
stable· 7 tests
Data sets — capture / switch / delete, applied as ONE undo step (§16.4)
data.dataset.palette
stable· 11 tests
Binding-expression DSL — lexer/parser/eval + 42 functions, registry-driven dispatch
data.expr.engine
stable· 49 tests
Governed-extract source (governed tables + optional metadata sidecar -> catalog)
data.governed.extract
stable· 2 tests
Locale-aware display formatting (en/de v1)
data.i18n.display
stable· 4 tests
Placeholder lowering — variable replacement + single-region dynamic table
data.lower.content
experimental· 11 tests
v43 lowering consumers — in-text variables (D-01), image place (D-14), live record-flow (D-12), rules (D-13)
data.lower.v43-consumers
experimental· 5 tests
Performance gates (§12.5) — engine-tier perf assertions
data.perf.gates
stable· 2 tests
paged.data bundle (media.paged.data) — manifest + activate + 3 panels + DuckDB query glue
data.plugin.bundle
experimental· 23 tests
Register as an SDK data provider (publish RecordSet to other consumers, e.g. sheets)
data.provider.contract
stable· 5 tests
Query engine (DuckDB-WASM) + RecordSet shape/order/hash — the Arrow seam
data.query.seam
experimental· 8 tests
Capability-gated data access + threat model (the suite's largest surface)
data.security.gates
experimental· 6 tests
Source adapters (inline + file at M0) + capability/consent gate + visible manifest
data.source.adapters
experimental· 12 tests
D-11 DB attach (SQLite/Postgres/MySQL) + DuckDB-WASM first-class engine + refresh-policy + remote
data.source.db-attach
experimental· 4 tests
Illustrator "Variables" — the four traits, mapped onto the shipped binding model (§16.4)
data.variable.traits
experimental· 5 tests

22 features · commit-pinned snapshot · the same rows the team plans by