Skip to main content
Integrations connect Pylon to the rest of your stack. Some are built-in subsystems selected by environment variables (file storage, email). Others are installable TS packages (Stripe, webhooks, feature flags). None of them are enabled through a manifest.plugins list.

File storage

File storage is a built-in subsystem selected by PYLON_FILES_PROVIDER, not a plugin entry.
The server validates these at boot. It fails at boot if a provider is selected without its required vars (e.g. PYLON_FILES_PROVIDER=s3 without the bucket or keys). It never silently degrades to local disk. local, stack0, and s3 are the providers that ship today. The s3 backend uses SigV4 presigned URLs for every operation. Clients PUT/GET bytes straight to the bucket (never through pylon’s memory). For a private bucket, pylon tracks per-file ownership. GET /api/files/<id> then enforces the same owner check as local disk before it 302-redirects to a short-lived presigned URL. Set PYLON_S3_PUBLIC_URL to serve from a public bucket/CDN instead. Credentials come from env only (no automatic IAM-role discovery). Pass PYLON_S3_SESSION_TOKEN alongside temporary credentials. Uploads use a 3-step direct-to-storage flow so large files never transit the server’s memory:
The shape is identical for every backend. Clients do not special-case Stack0 vs local. Persist both stored.url (display) and stored.id (so you can DELETE /api/files/<id> later).
  • GET /api/files/<id> serves the bytes. For CDN backends pylon 302-redirects to the CDN URL; for local it streams from disk.
  • DELETE /api/files/<id> removes the asset. Owner-gated: only the user who confirmed the upload (or an admin).
From the browser, uploadFile in @pylonsync/react runs all three steps, and <FileUpload> in @pylonsync/client wraps it:

Visibility

visibility on /api/files/init decides who can read the file through GET /api/files/<id> on backends that track ownership (local disk, a private S3 bucket): Use "public" for files every visitor sees, such as feed photos or listing images. Writes and deletes stay with the uploader either way. Any other value is refused with 400 INVALID_VISIBILITY. On Stack0 and on a public bucket, stored.url is a CDN URL that anyone can load, whatever the visibility.
The multipart POST /api/files/upload was removed in 0.3.91 and returns 410 Gone. uploadFile used it until 0.11.2; update @pylonsync/react if <FileUpload> fails with that status.

Email

Transactional email is a built-in subsystem selected by PYLON_EMAIL_PROVIDER, not a plugin entry.
Send from an action via ctx.email. Both forms work. Use positional send(to, subject, body) for plain text, or an options object for HTML and attachments:
Limits: one recipient per send, at most 20 attachments and 15MB of base64 attachment data (≈11MB raw) per email. Larger sends throw EMAIL_TOO_LARGE before any network I/O. Auth-flow email (magic codes, verification, invites) uses a separate channel read from PYLON_AUTH_EMAIL_*. It falls back to PYLON_EMAIL_*. This keeps a shared platform auth key away from app code. See Auth → Email verification.

Stripe billing

Billing is the installable @pylonsync/stripe package. It provides plans, checkout, a billing portal, a signature-verified webhook, and a subscription entity. Full config, hooks, and the webhook endpoint are on its page.

Outbound webhooks

Outbound webhooks to your customers’ endpoints are the installable @pylonsync/webhooks package. It provides Svix-compatible HMAC signatures, an exponential-backoff retry schedule, secret rotation, and a delivery-audit entity. See its page.

Feature flags

Runtime feature flags are the installable @pylonsync/feature-flags package. It provides local-eval boolean and multivariate flags, percentage rollouts, and targeting predicates. See its page.

Audit log

Auditing is a built-in framework feature, not a plugin. The /api/auth/audit and /api/auth/audit/tenant routes expose the log. Pylon records sensitive auth events automatically.

Caching

Pylon keeps an in-process cache that backs SSR / ISR response caching. It is internal to the runtime today. There is no user-facing ctx.cache API. For app-level memoization, cache inside a server function’s own logic, or use an external store you call from a function.