Loading
There are two front doors for getting your Particles into a running server: load
them at startup (--python-functions), or deploy them durably over the
wire (particledb particles deploy). Both run the same collector, so the SQL
signatures are identical wherever they are produced.
Load at startup — --python-functions
Section titled “Load at startup — --python-functions”Pass --python-functions when starting the server. Each
@scalar / @aggregate / @window-decorated function in the target is
discovered, its signature built from the type hints, and it is registered so it
is callable from SQL. The flag is repeatable and accepts a file, a package
directory, or a dotted module name:
# A single module fileparticledb start --python-functions ./particles/text.py
# A whole package directory (every *.py, non-underscore, is scanned)particledb start --python-functions ./particles
# A dotted module name (must be importable)particledb start --python-functions geo.distance
# Repeatable — combine several sourcesparticledb start \ --python-functions ./particles \ --python-functions geo.distanceAfter startup the discovered functions resolve directly from SQL — nothing else to run:
SELECT domain_of('kyle@jepsen.io'); -- 'jepsen.io'SELECT slugify('Hello, World!'); -- 'hello-world'Startup-loaded Particles go through the same internal registry as a durable
deploy, and are audited as the system principal.
Verify locally — particledb particles verify
Section titled “Verify locally — particledb particles verify”verify runs the discovery + signature stages locally and prints what it
found. It makes no server call — use it to sanity-check a module before
deploying:
particledb particles verify ./particlesdiscovered 1 module(s), 2 particle(s) domain_of(text) -> text [scalar, immutable, strict] slugify(text) -> text [scalar, immutable, strict]Add --json for the full machine-readable manifest (useful in CI):
particledb particles verify ./particles --jsonIf a function is missing a type hint or uses an unsupported one, verify fails
with a plain, source-located message — you fix your module, not the database.
Deploy durably — particledb particles deploy
Section titled “Deploy durably — particledb particles deploy”deploy discovers your Particles and binds each one durably in a running
server. It connects over the PostgreSQL wire control channel and persists each
binding on the crash-atomic DDL/WAL path — so it survives a restart without
re-passing --python-functions.
# Deploy to a local server (default target 127.0.0.1:5432)particledb particles deploy ./particles
# Explicit target, namespace, and versionparticledb particles deploy ./particles \ --namespace public \ --version 1 \ --target db.internal:5432Common flags:
| Flag | Meaning |
|---|---|
--target host:port | Server to deploy to (default 127.0.0.1:5432). |
--namespace <name> | Catalog schema to bind into (default: server default, typically public). |
--version <v> | Explicit binding version (omit → server auto-assigns). |
--dry-run | Run discover + signature build, print the exact bindings, make no server call. |
--json | Machine-readable output for CI. |
--no-sign | Skip signing (default for a dev server). |
Connection defaults follow the standard PostgreSQL environment variables
(PGUSER, PGDATABASE, PGPASSWORD); the user/database default to
particledb.
A --dry-run shows exactly what would be bound without touching the server:
particledb particles deploy ./particles --dry-rundiscovered 1 module(s), 2 particle(s) domain_of(text) -> text [scalar, immutable, strict] slugify(text) -> text [scalar, immutable, strict]namespace: public
(dry-run) discovered + signatures built; no server call made. would bind: domain_of(text) -> text [scalar] would bind: slugify(text) -> text [scalar]Next steps
Section titled “Next steps”- Collisions & Error Handling — what happens when a Particle name matches a built-in, plus null and error semantics.
- Best Practices — how to think about writing a Particle.
- Python — the decorators and tested examples.