Jadpo is experimental and not ready for production. These docs follow the compiler's main branch as of 30 Oct 2026. What's built · Install 0.1.0
jadpo
Reference: External services

External services

How packages, connections, capabilities and services fit together

On this page

Seven terms name the ways an app reaches past its own code: package, provider, connection, driver, capability, built-in service and service run by Jadpo. This topic says what each one is and where it runs. The topics it links hold the rules.

Most apps use only two of them. A connection in app.jadpo opens a database or a provider's API, and your actions call through it. You don't need Docker or Podman for any of this: only a service run by Jadpo uses a container.

What each one is

Term What it is Declared in Runs
Package Jadpo source shared between apps, laid out as shared/ is. A library package holds types, failures and pure functions (Postcodes.uk.parse); a provider package describes one outside API: its operations, types, failures, webhook events and how it is reached (Kinds of package, The package format) packages/<name>/<version>/ when installed; the app's own in shared/providers/ Compiled into the app and run in its process. A package is never a process, a container or native code of its own
Provider The outside API a provider package describes: Stripe, a courier, another Jadpo app, Gotenberg. The package's provider.jadpo says how it is reached Nowhere in the app: it is the other end of the call Wherever its owner runs it: on the internet (hosts:), at an address a setting gives (host: on the connection), or in a container Jadpo starts (runs:)
Connection One named entry in connections: in app.jadpo: a built-in driver (driver: Driver.x) or a provider package (package: X.vN), with its settings, its credential and the domains whose actions may call it. One connection is one resource: a database, a bucket, one account at a provider (Connecting in app.jadpo) app.jadpo, its values read from config.jadpo settings Opened by the runtime, inside the app
Driver Native code in Jadpo's runtime that speaks one protocol: PostgreSQL, SMTP, the disk, Cloudflare Queues, OpenAI-compatible model servers; Redis, S3 and OpenID Connect to come. Drivers arrive only with a Jadpo release, never in a package (No presets, no dependencies) driver: on a connection Inside the app, talking to a server the operator runs
Capability A job Jadpo itself does, with one API in app code whatever fills it: database, cache, files, email, search, documents, ai and the rest. One connection fills it: a driver, or a provider package whose provides/<capability>.jadpo maps the job onto its operations (Capabilities) Chosen in app.jadpo: email: { connection: mail }, store: sheets on a File field Wherever the connection that fills it runs
Built-in service A backend feature Jadpo provides, so the app installs nothing: feature flags, rate limits, files, email, audit, telemetry, search, documents, bot protection (Built-in services). Email, files, search and documents do their outside work through a capability; flags, rate limits and audit keep their state in the app's own stores Where Built-in services says: flags.jadpo, rate_limit:, type X = EmailMessage, File fields Inside the app's runtime. It is a feature, not a process or a container
Service run by Jadpo A provider whose API is a stateless container image, declared by runs: in its package's provider.jadpo (Gotenberg turning HTML into PDFs, ClamAV scanning uploads). Jadpo starts and supervises the container through Docker or Podman and hands its connection the address (Services) runs: in the package, named by a connection A container beside the app on the same machine

Two words mean two things each:

  • "Service". A built-in service is part of Jadpo's runtime, inside the app's process; a service run by Jadpo is a container beside it. No built-in service starts a container; one can use a service run by Jadpo through its capability, as documents can use Gotenberg.
  • runs:. In a package's provider.jadpo it declares a container; on a deployable in app.jadpo it lists the background work that deployable runs, runs: [Trigger.schedules] (Declared deployables).

How they relate

text
the app's process: jadpo dev's interpreter, or a native or Workers deployable│├── domain code ── calls ──► library package             pure functions, in process│├── domain code ── calls ──► connection: provider package ── HTTPS ──► provider's API│                                                    on the internet (hosts:), at host:,│                                                    or in a container Jadpo runs (runs:)│└── built-in services: flags, rate limits, email, files, search, documents, ...       │ outside work goes through a capability       └──► capability: email, files, database, documents, ai, ...              filled by one connection, either              ├── a built-in driver ──────────── its protocol ──► a server the operator runs:              │                                                  PostgreSQL, SMTP, S3              └── a provider package's provides/ ── HTTPS ──────► provider's API:                                                                 Resend, Postmark, Gotenberg
  • Code calls a provider's operations only through a connection, from an action in a domain the connection lists: couriers.bookings.create(...) (Calling).
  • Code never names what fills a capability. It writes an EmailMessage type or a File field, and app.jadpo picks the connection, so changing provider changes app.jadpo and its settings, never domain code.
  • One provider package can be both. Postmark fills email through provides/email.jadpo, and the domains its connection lists call its own operations (hosted templates, suppression lists) as any provider's.
  • Packages fill capabilities and never invent them, never bring a driver and never depend on another package.
  • Anything that keeps data is the operator's. PostgreSQL, Redis, an S3 bucket and an SMTP server are reached through a driver at the address a setting gives; Jadpo never runs them. A service run by Jadpo holds no data, and each app instance runs its own copy.

Where each runs

jadpo dev jadpo test Native deployable Workers deployable
Library package In process In process Compiled in Compiled in
Provider package's calls Faked by default, from its recordings or generated answers; operations named in development: { sandbox: } go to the sandbox, never live (Provider calls in development) Always faked; a test scripts answers with fakes: (Tests and fakes) HTTPS to the live or sandbox host the connection's environment: picks, or to its host: The same, through the Worker's fetch
Database, Driver.postgres The address its setting gives, else a disposable PostgreSQL started from the machine's PostgreSQL tools A copy per test on a disposable PostgreSQL, or on JADPO_TEST_DATABASE_URL's server The operator's PostgreSQL The operator's PostgreSQL, through Hyperdrive
Email, by SMTP or a mail package Caught in the dev inbox Caught in email.sent The SMTP server, or the mail package's API The same; SMTP on port 587 only
Files The disk driver, in .jadpo/files/ An in-memory store The disk (one server) or S3 S3, R2 included
Service run by Jadpo, runs: Started as a container by jadpo dev Never started: the package's fake answers A container beside the app: jadpo build writes the configuration that runs it (Compose first), then the deployable supervises it itself None: Workers runs no containers, so the connection gives host: where the service is hosted elsewhere

jadpo check refuses a deployable whose target can't run a connection it reaches, naming what to use instead: on Workers the disk, a service run by Jadpo without host:, and SMTP on port 25 (Capabilities, "Targets").

How Docker fits

  • An app needs no Docker or Podman to be checked, tested, run in jadpo dev or built. Nothing above but a service run by Jadpo uses a container: the disposable PostgreSQL comes from the machine's own PostgreSQL tools, a native deployable is one binary (A native deployable) and a Workers deployable is a Worker. Neither is an image.
  • Docker or Podman comes in only for a service run by Jadpo. Jadpo talks to whichever engine the machine has, through the Docker-compatible API both serve. It creates each container itself. A container has no outbound network until its connection grants it, is never privileged and can't reach the host's disk. A new or changed image runs only once a person accepts it in the approval report. jadpo services lists, starts and stops each one and shows its logs (Tooling). You never write a Dockerfile or a Compose file, and an app with no such connection never needs an engine (Services).
  • The operator's infrastructure is their own. They may run PostgreSQL or an SMTP server in Docker, or anywhere else; the app sees only the address its setting gives.

In an app

One app with each kind of connection: a database on the PostgreSQL driver, mail on the SMTP driver filling the email capability, and the app's own provider package for a courier, which the shipping domain calls:

example
application {    connections: {        main: {            driver: Driver.postgres            url: config.database_url        }        mail: {            driver: Driver.smtp            host: config.smtp_host            credential: {                username: config.smtp_username                password: config.smtp_password            }        }        couriers: {            package: AcmeCouriers.v1            domains: [shipping]            credential: config.couriers_api_key            environment: config.couriers_environment        }    }    email: {        connection: mail        from: config.mail_sender    }}
example
use app { couriers }use shipping/failures { SlotGone }use shared/providers/acme_couriers/// Books a collection with the courier, through its connection.action book(postcode: AcmeCouriers.Postcode) fails SlotGone -> AcmeCouriers.Booking {    return attempt couriers.bookings.create(        AcmeCouriers.CreateBooking {            postcode: postcode        }    ) {        slot_taken: SlotGone    }}

A service run by Jadpo: Gotenberg's package declares its container, and a connection to it fills the documents capability. In jadpo dev and a native deployable, Jadpo starts the container. On Workers the connection would give host: instead:

example
// packages/gotenberg/v8/provider.jadpo/// Gotenberg's HTTP API, run by Jadpo as a container beside the app.provider {    protocol: Protocol.multipart_http    runs: {        image: "gotenberg/gotenberg:8@sha256:…"        port: 3000        asks: ["fonts.googleapis.com"]    }}// app.jadpoapplication {    connections: {        pdfs: {            package: Gotenberg.v8            domains: [billing]            outbound: ["fonts.googleapis.com"]        }    }    documents: {        connection: pdfs    }}

What is built of these

Built: library and provider packages, installed from a folder or git and locked; connections and the network report; provider calls with decoding, retries and idempotency keys; fakes in development and tests, recordings and sandbox calls; webhooks, queues, polls and package actions; the drivers for PostgreSQL, SMTP, the disk (in jadpo dev and tests), Cloudflare Queues and OpenAI-compatible servers; the database, email (SMTP, Resend and other mail packages), receiving, schedules and ai capabilities; and the built-in services email, rate limits and the first part of files.

Not built yet: services run by Jadpo (runs:, jadpo services, and with them every use of Docker or Podman); the Redis and S3 drivers and a deployable's disk; OpenID Connect sign-in providers and OAuth grants; the cache, publishing, search, documents, bot_check and scanning capabilities; the built-in services flags, audit, telemetry's section, search, documents and bot protection; the hosted registry; importers other than openapi; and choosing a provider when deploying. Each page's "What is built" table is the record.

Markdown for agents: /docs/how-integrations-fit-together.md.Built from Jadpo main at a707efb.