Jadpo is experimental and not ready for production. These docs follow the compiler's main branch as of 5 Nov 2026. What's built · Install 0.3.0
jadpo
ReferenceExternal services

External services

How packages, connections, capabilities and services fit together

On this page

Here is an app calling one outside API, with nothing left out: it books a collection with a courier. Acme Couriers publishes no package, so the app describes its API itself, in shared/providers/. With an installed package, jadpo package add brings these package files and you write only the connection, the setting and the action.

The connection goes in app.jadpo. connections: and its keys are built in, couriers is your name for it, AcmeCouriers.v1 is the package below, and shipping is the domain whose actions may call it.

app.jadpo:

example
application {    connections: {        couriers: {            package: AcmeCouriers.v1            domains: [shipping]            credential: config.couriers_api_key            environment: config.couriers_environment        }    }}

The secret and which of the courier's hosts to use are settings. ProviderEnvironment is built in, and is .sandbox or .live.

config.jadpo:

example
config {    couriers_api_key: Text {        secret: true    }    couriers_environment: ProviderEnvironment {        default: ProviderEnvironment.sandbox    }}

The package names itself and says how the API is reached.

shared/providers/acme_couriers/v1/package.jadpo:

example
/// Acme Couriers' booking API, written from its documentation.package AcmeCouriers.v1 {    licence: Licence.proprietary    jadpo: "1.0"}

licence: is required, and Licence.proprietary suits a package only your app uses. jadpo: is also required: it is the lowest Jadpo version the package says it needs, a major and minor number as text. Jadpo checks only that form and compares the number with nothing yet, so "1.0" passes on every release, even one before 1.0.

shared/providers/acme_couriers/v1/provider.jadpo:

example
/// Acme Couriers' booking API.provider {    protocol: Protocol.json_http    hosts: {        live: "https://api.acme-couriers.example"        sandbox: "https://sandbox.acme-couriers.example"    }    credential: CredentialScheme.bearer}

A resource is a group of the API's operations. This one has one operation, which takes a CreateBooking and answers with a Booking, two types the package declares. changes: true says the call changes something at the courier. idempotent: true says the call is safe to send again, here because repeating it books one collection, so Jadpo may retry it. source: PackageSource.written tells whoever reviews the package that a person wrote this operation from the courier's documentation, rather than importing it (Provenance and confirmation).

shared/providers/acme_couriers/v1/resources/bookings.jadpo:

example
public resource bookings {    create: {        method: HttpMethod.post        path: "/v1/bookings"        input: CreateBooking        output: Booking        changes: true        idempotent: true        source: PackageSource.written    }}

shared/providers/acme_couriers/v1/types/create_booking.jadpo:

example
/// What booking a collection takes.public type CreateBooking = Object {    postcode: Text}

shared/providers/acme_couriers/v1/types/booking.jadpo:

example
/// A booked collection.public type Booking = Object {    id: Text}

The action calls the operation through the connection. use app brings in the connection, and use shared/providers/acme_couriers brings in the package, whose public names are written AcmeCouriers.<name>.

domains/shipping/actions/book.jadpo:

example
use app { couriers }use shared/providers/acme_couriers/// Books a collection with the courier, through its connection.action book(request: AcmeCouriers.CreateBooking) -> AcmeCouriers.Booking {    return couriers.bookings.create(request)}

Run jadpo records update once, which writes down the hosts the app can reach, then check the project:

shell
jadpo check
output
Not yet confirmed  Record each with `jadpo package record`, which checks a sandbox answer  against its types (agent)    couriers.bookings.createchecked: 1 unconfirmed, 8 files

The check passes. "Not yet confirmed" means no real answer from the courier has been checked against the types you wrote, so they are only as right as what you read. It doesn't fail the check, and jadpo approval shows a person what ships unconfirmed. To confirm the call, put a sandbox key in .env.local and run jadpo package record couriers bookings.create --input '{"postcode": "M1 1AA"}', which calls the sandbox once, checks the answer and keeps it as a recording in the package (Provenance and confirmation).

A database and mail are connections too. They use a driver built into Jadpo, so there is no package to write. email: says which connection sends the app's email, whichever provider it is, which makes email a capability.

app.jadpo:

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            }        }    }    email: {        connection: mail        from: config.mail_sender    }}

config.jadpo:

example
config {    database_url: PostgresUrl    mail_sender: Email    smtp_host: Hostname    smtp_password: Text {        secret: true    }    smtp_username: Text}

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. 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:), or at an address a setting gives (host: on the connection)
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 store of files, 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, OpenID Connect. Redis and S3 aren't built yet. 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, email, files, 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, search (Built-in services). Email, files and search 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

A service run by Jadpo is a seventh term, for a thing that isn't built yet: Running a service in a container.

Two words that mean two things

runs: is one key with two jobs, depending on where it is written:

Written on It says Looks like Built
A deployable, in app.jadpo Which background work that deployable runs (runs:) runs: [Trigger.schedules] Yes
A provider, in a package's provider.jadpo The container Jadpo starts for that provider (Running a service in a container) runs: { image: "…" port: 3000 } Not yet

"Service" has two meanings too. A built-in service, such as feature flags, is part of Jadpo's runtime, inside the app's process. A service run by Jadpo would be a container beside it, and isn't built yet.

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:), or at host:│└── built-in services: flags, rate limits, email, files, search, ...       │ outside work goes through a capability       └──► capability: email, files, database, ai, ...              filled by one connection, either              ├── a built-in driver ──────────── its protocol ──► a server the operator runs:              │                                                  PostgreSQL, SMTP              └── a provider package's provides/ ── HTTPS ──────► provider's API:                                                                 Resend
  • 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. Resend's fills email through provides/email.jadpo, and the domains its connection lists can call its own operation, emails.send, 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 and an SMTP server are reached through a driver at the address a setting gives; Jadpo never runs them. The operator may run them in Docker or anywhere else, and the app sees only the address.

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 driver, on one server None yet: Workers has no disk, and the S3 driver isn't built

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

An app needs no Docker or Podman to be checked, tested, run in jadpo dev or built. 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.

What is built of these

Of what this page describes, these aren't built yet: running a service in a container; the Redis and S3 drivers; OAuth grants; the cache, publishing, documents, bot_check and scanning capabilities; an outside engine for search; the hosted registry; importers other than openapi; and choosing a provider when deploying.

Of the built-in services, flags, rate limits, files, audit and search are partly built, email is built, and documents, bot protection and the telemetry: section aren't built yet. Each page's "What is built" table is the record: this page's What is built and Built-in services'.

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