Overview

How Voltro plugins compose into the runtime, what they can intercept, the catalogue, and writing your own.

A Voltro plugin is a server-side extension that hooks into the runtime. Plugins can intercept mutations / queries / actions, contribute schema mixins + tables + migrations, mount raw-HTTP and inspect routes, contribute an Effect service layer, and run install / activate / deactivate lifecycles.

The framework ships some plugins; you write your own; the contract is small enough to learn in a single read.

What's in this section

  • The plugin contractdefinePlugin, lifecycle hooks, rpc interceptors, framework-version compatibility
  • plugin-audit — mutation audit log + audit() mixin
  • plugin-auth — full auth suite: password (rehash-on-verify) + sessions (multi-key rotation + sliding-window) + magic-link/reset + passkeys (atomic clone detection, BYO multi-replica challenge store) + CSRF + session revocation + memberships/switch-tenant + TOTP/MFA (sign-in enforcement + recovery codes), mounted by authRoutesPlugin() (see also the Authentication section)
  • plugin-multitenancytenant() schema mixin + assertOwnTenant write-guard + TenantMismatch
  • plugin-soft-deletesoftDelete() schema mixin (hide on delete, hardDelete() bypass)
  • plugin-rbac — roles + permissions + the permission() guard
  • plugin-ratelimit — per-endpoint / per-subject / per-tenant request limits
  • plugin-billing — subscriptions, plans, entitlements + usage metering (Stripe + mock provider); seat-based billing on Stripe's own proration, retries, tax and checkout; money as integer minor units
  • plugin-licensing — offline-verified EdDSA license keys + cloud-issued entitlement snapshots that feed plugin-billing; plan entitlements + pricing decided server-side, never baked into a published version
  • plugin-mail — transactional email (Resend / Postmark / SendGrid / SES / Mailgun / SMTP, templates, suppression, scheduling, batch, idempotency)
  • plugin-storage — file storage: public (CDN-direct) + private (access policy + per-object grants), S3 / R2 / GCS / MinIO / filesystem
  • plugin-ai-flows — durable multi-step AI pipelines (deterministic + agentic) with human-in-the-loop, chaining, and cadence; code-first defineFlow or data-driven rows
  • plugin-postgis — postgres-native geography / geometry columns + spatial operators
  • plugin-broadcast — cross-replica reactivity over a pub/sub bus (Redis / NATS) for non-postgres dialects
  • plugin-webhooks — durable incoming + outgoing webhooks (HMAC signing, retries, idempotency)
  • plugin-atlassianJiraService + ConfluenceService over the Atlassian APIs
  • plugin-deactivationdeactivation() schema mixin (visible, can't log in)
  • plugin-prometheus — Prometheus exporter at GET /metrics; scrapes the unified Metrics-API (the same source the dashboard Metrics panel reads)
  • plugin-datadog — deep Datadog integration; agentless metrics + opt-in logs + traces (OTLP→Agent) + profiler, trace-correlated
  • plugin-sentry — deep Sentry integration; trace-correlated errors + breadcrumbs from the log sink + opt-in performance traces
  • plugin-flags — feature flags: per-subject / per-tenant targeting, deterministic % rollouts, kill-switch, declarative rpc gating + client UI gating
  • plugin-notifications — unified notifications: one send API across email / Slack / SMS / push (first-class APNs/FCM factory) / in-app, channel preferences + in-app inbox, digest/batching, quiet hours, broadcast/topics, durable DataStore-backed store by default
  • plugin-logship — ship structured logs to Better Stack / Axiom / Loki / any HTTP sink; batched, redacted, fail-soft
  • plugin-moderation — moderate user content before commit: keyword or AI provider, block / flag via interceptor + in-handler redact
  • plugin-search — keep an external index (Typesense / Meilisearch / Algolia) in sync via the ChangeEvent tap; tenant-scoped search.query + hook
  • plugin-cdc-out — declarative reverse-ETL: mirror table changes outward to a webhook / Kafka / Snowflake / BigQuery sink through a durable outbox; ordered per pipe, at-least-once from enqueue, dead-lettered
  • plugin-governance — data governance: retention TTL sweep, GDPR export + erasure, consent ledger, field encryption
  • plugin-openapi — OpenAPI 3.1 spec + Swagger-UI docs generated from your defineRestRoute descriptors and (opt-in) rpc procedures
  • plugin-versioning — full row history + time-travel (rowHistory / rowAsOf / restoreAsOf / diffVersions); what-changed-to-what on every write
  • plugin-presence — ephemeral realtime presence: heartbeat roster per channel + usePresence / useTyping hooks, cross-instance
  • plugin-scim — SCIM 2.0 provisioning (Users + Groups at /scim/v2) so an enterprise IdP can create/deactivate users
  • plugin-sso-saml — enterprise SAML 2.0 SSO: SP-initiated login + Single Logout, ACS, metadata (+ IdP-metadata-URL auto cert rotation, encrypted assertions, SP request signing); mints a framework session
  • API keysfirst-class (not a plugin): apiKeys: true enables Bearer-key auth + admin-gated issue/list/revoke
  • Analytics & warehouse sinksAnalyticsSink contract + five first-party sink plugins (postgres-lite, DuckDB, ClickHouse, Tinybird, PostHog)
  • External identity providers — the six auth-adapter packages (WorkOS, Kinde, Clerk, Auth0, Supabase, generic OIDC)

The catalogue at a glance

Status legend: ✓ shipped · ◐ partial · — planned.

Plugin Status What it does
@voltro/plugin-audit Mutation audit log + audit() mixin
@voltro/plugin-auth Full auth suite via authRoutesPlugin(): password (rehash-on-verify), sessions (multi-key rotation + sliding-window), magic-link + password-reset, passkeys/WebAuthn (atomic clone detection, BYO multi-replica challenge store), CSRF, session enumeration + revocation, memberships + switch-tenant, TOTP/MFA (sign-in enforcement + recovery codes); authTables schemas
@voltro/plugin-multitenancy tenant() schema mixin (read-scope + write-fill) + assertOwnTenant guard + typed TenantMismatch
@voltro/plugin-soft-delete softDelete() schema mixin — deletedAt / deletedBy; delete → UPDATE, hardDelete() bypass
@voltro/plugin-rbac Roles compile to scopes + the permission() handler guard + typed ScopeError
@voltro/plugin-ratelimit Per-endpoint / per-subject / per-tenant limits; sliding-window / fixed-window / token-bucket; memory / postgres / redis stores
@voltro/plugin-billing Subscriptions, plans, entitlements + usage metering over a pluggable provider (Stripe + mock); seat-based billing; proration, failed-payment retries, tax and the checkout seat stepper are Stripe's, via the official SDK; requireEntitlement() guard + enforce interceptor; /billing/webhook via plugin-webhooks; money as integer minor units
@voltro/plugin-mail Transactional email — Resend / Postmark / SendGrid / SES / Mailgun / SMTP, *.email.tsx templates, per-tenant suppression, send-time scheduling, bulk/batch send, per-send idempotency, durable via workflows
@voltro/plugin-storage File storage — public (CDN-direct) + private (access policy + per-object grants), S3 / R2 / GCS / MinIO / filesystem providers, presigned URLs, listRefs browse/search, HTTP Range (206) serving, dashboard browser
@voltro/plugin-postgis Postgres-native geography / geometry columns + spatial predicates (ST_DWithin, ST_Contains, ST_Intersects); GiST indexes via .expressionIndex(..., { kind: 'gist' }). No ST_Distance projection yet. Postgres-only by design (fails loud elsewhere). → details
@voltro/plugin-broadcast Cross-replica reactivity — fans out app-mutation change events to every replica over a pub/sub bus (Redis / NATS). Closes the single-instance gap for every non-postgres dialect. → details
@voltro/plugin-webhooks Incoming + outgoing webhooks — defineIncomingWebhook (signature verify + idempotency, Stripe/GitHub/Slack presets) and defineOutgoingEvent (durable delivery workflow, HMAC signing, retries, filters). → details
@voltro/plugin-auth-{workos,kinde,clerk,auth0,supabase,oidc} Six IdP adapters over the shared jwtBearerStrategy — JWKS verify + claims→tenant mapping; WorkOS additionally ships hosted-login OAuth primitives (workosAuthorizationUrl / workosAuthenticateWithCode) for a redirect-based SSO login flow. → details
@voltro/plugin-analytics-postgres First-party lite — events on the main DataStore, cross-dialect (postgres / mysql / mariadb / mssql / sqlite / turso). → details
@voltro/plugin-duckdb Embedded DuckDB sidecar — real OLAP performance, no external service. → details
@voltro/plugin-clickhouse Production OLAP via the official ClickHouse client. → details
@voltro/plugin-tinybird Hosted ClickHouse via Events API + Pipes. → details
@voltro/plugin-posthog Product analytics — track-only; compose with another sink for reads. → details
@voltro/plugin-atlassian JiraService + ConfluenceService over the Atlassian REST / Greenhopper / Agile APIs — PAT or OAuth 2.0 (3LO) auth, transient retry, SSRF guard, comment-write, signature-verified inbound webhooks, avatar proxy, per-tenant cache. → details
@voltro/plugin-deactivation deactivation() schema mixin — deactivatedAt + deactivatedBy (→ Actor); subject can't log in but data stays visible. → details
@voltro/plugin-prometheus Prometheus exporter — GET /metrics in text exposition format over the unified Metrics-API (Effect MetricRegistry); counters / histograms / gauges + custom metrics, optional bearer gate + node process metrics. → details
@voltro/plugin-datadog Deep Datadog integration — agentless metrics push to /api/v2/series + opt-in logs (/api/v2/logs, dd.trace_id-correlated) + traces (OTLP→Agent) + dd-trace profiler; DD_API_KEY/DD_SITE + unified service tagging, fail-soft. → details
@voltro/plugin-sentry Deep Sentry integration — mutation/query/action errors reported correlated to the active trace (trace_id + span_id) + breadcrumbs from the framework log sink; opt-in performance traces (SentrySpanProcessor, OTel-consumer mode) + profiler. @sentry/* optional + lazy. → details
@voltro/plugin-flags Feature flags — per-subject / per-tenant targeting + deterministic % rollout (FNV-1a bucket) + kill-switch; multivariate variant flags + scheduled / ramping rollouts + a durable kill-switch audit trail; declarative gatedBy (typed FlagDisabled) + requireFlag guard + flags.evaluate / flags.variants routes + useFlags/useFlag/useVariant hooks; memory / postgres store. → details
@voltro/plugin-notifications Unified notifications — one send across email / Slack / SMS / push (first-class pushChannel APNs/FCM factory) / in-app channels, per-user channel preferences, in-app inbox + unread count + delivery records; digest/batching rollup, per-subject quiet hours (DND), broadcast/topic fan-out; NotificationService + useInbox/useUnreadCount/useMarkRead/useTopicSubscription/useQuietHours hooks; durable DataStore-backed store by default (auto-migrated notification_* tables). → details
@voltro/plugin-logship Ship structured logs to Better Stack / Axiom / Loki / any HTTP sink — rides the log-sink hook, batched + redacted + fail-soft, trace-correlated. → details
@voltro/plugin-moderation Content moderation — keyword denylist or AI provider (fails open), block (typed ContentRejected) / flag via rpc interceptor + in-handler moderate() redact helper. → details
@voltro/plugin-search External search index sync — rides the ChangeEvent tap to mirror tables into Typesense / Meilisearch / Algolia (memory default), tenant-scoped search.query action (facets · highlighting · fuzziness · range/negation filters · engine-param passthrough) + useSearch hook + backfillIndex + durable cross-replica sync stats. → details
@voltro/plugin-cdc-out Declarative reverse-ETL — mirror table changes outward to external sinks (webhook / Kafka / Snowflake / BigQuery) through a durable outbox; ordered per pipe, at-least-once from enqueue, retried with backoff, dead-lettered. Engine + memory/webhook sinks shipped; warehouse connectors implement the CdcSink interface.
@voltro/plugin-governance Data governance — retention TTL sweep (delete / anonymise), GDPR subject export + erasure (admin-gated routes + GovernanceService), consent ledger, field encryption. → details
@voltro/plugin-openapi OpenAPI 3.1 spec (GET /openapi.json) + Swagger-UI (GET /docs) generated from defineRestRoute descriptors AND (opt-in) rpc procedures (queries/mutations/actions/streams → POST /rpc/<name>) — input/output/error Schemas via JSONSchema.make. → details
@voltro/plugin-versioning Full row history + time-travel — value snapshot of every insert/update/delete on listed tables into _voltro_row_history (rides the ChangeEvent tap); rowHistory / rowAsOf queries + restoreAsOf / diffVersions; TTL + per-row cap retention. → details
@voltro/plugin-presence Ephemeral realtime presence — heartbeat roster per channel (presence.heartbeat/list/leave + usePresence), a useTyping typing indicator, swept _voltro_presence table, cross-instance. → details
@voltro/plugin-scim SCIM 2.0 provisioning — Users + Groups REST at /scim/v2 (bearer-gated) incl. group-membership PATCH/PUT + the RFC 7644 discovery trio (ServiceProviderConfig/Schemas/ResourceTypes), userName/externalId/displayName eq filters, pagination, unique userName, active:false deactivation; scim_users/scim_groups. → details
@voltro/plugin-sso-saml Enterprise SAML 2.0 SSO — SP-initiated login + Single Logout (both directions) + ACS + SP metadata under /saml; IdP-metadata-URL auto cert rotation, encrypted assertions, clock-skew, SP request signing. Signature verify via @node-saml/node-saml (optional+lazy), mints a framework session. → details

API keys are first-class (not a plugin): apiKeys: true in app.config.ts → Bearer-key auth + admin-gated /v1/api-keys management, hash-only storage. → details

Every plugin carries a design doc in the framework's plans/ directory before it ships.

Configuration shape

// app.config.ts
import { auditPlugin } from '@voltro/plugin-audit'
import { rateLimitPlugin } from '@voltro/plugin-ratelimit'

export default {
  type: 'api' as const,
  name: 'api',
  plugins: [
    rateLimitPlugin({ default: { limit: 60, window: '1m' } }),
    auditPlugin({ sink: 'console' }),
  ],
}

Order matters: the framework composes outer→inner, so the rate-limit interceptor runs before the audit interceptor sees the request. Rejected requests never enter the audit log.

What plugins can do

Surface What it lets you do
interceptMutation / interceptQuery / interceptAction Wrap every mutation / query-setup / action — gate, audit, transform input/output.
extendSchema Contribute tables + custom SQL migrations (tracked in _voltro_plugin_migrations).
services Provide an Effect Layer whose Tags every handler can yield* (e.g. MailService, StorageService).
routes Register plugin-owned rpc queries / mutations / actions (alias-prefixed tags).
httpRoutes Serve public raw-HTTP endpoints on the framework listener (e.g. GET /_voltro/storage/:id).
inspectEndpoints Mount tooling under /_voltro/inspect/plugins/<alias>/….
onScheduleFire / onWorkflowStep / onHttpRequest Wrap every cron firing, every workflow step(), every pre-auth HTTP request.
onInstall / onActivate / onDeactivate / onUninstall Lifecycle hooks at first-install, boot, shutdown, and removal.
Schema mixins (defineMixin) The OTHER plugin shape — audit(), tenant(), softDelete() — declared in @voltro/database, not via the runtime contract.

When NOT to write a plugin

  • One-off side effect — just call it from the mutation directly.
  • App-specific behaviour — keep it in app code, not a reusable plugin.
  • Anything cross-cutting that only affects ONE mutation — a single await ctx.audit.log(...) call beats a plugin's hook.

Plugins are for cross-cutting concerns. Audit-log every write, rate-limit every mutation, send a user.created event from every sign-up: that's plugin territory.