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

Connecting in app.jadpo

A connection is how your app reaches a database, a mail server or a provider's API. You declare each one once, in connections: in app.jadpo. Each entry is either a built-in driver (driver: Driver.x) or a package (package: X.vN), with the typed settings that driver or package declares. A connection to a package also names the domains whose actions may call it, the credential from config.jadpo, and which of the package's hosts to use.

example
// app.jadpoapplication {    connections: {        main: {            driver: Driver.postgres            url: config.database_url        }        stripe: {            package: Stripe.v2024_06_20            domains: [payments]            credential: config.stripe_secret_key            environment: config.stripe_environment            webhooks: {                secret: config.stripe_webhook_secret            }            erasure: {                key: User.stripe_customer_id            }            development: {                sandbox: [payment_intents.retrieve, customers]            }        }        couriers: {            package: AcmeCouriers.v1            domains: [shipping]            credential: config.couriers_api_key            environment: config.couriers_environment            timeout: 5s        }        rates: {            package: ExchangeRates.v1            domains: [finance]            credential: config.rates_key            polls: {                latest: 6h            }        }        pdfs: {            package: Gotenberg.v8            domains: [billing]            outbound: ["fonts.googleapis.com"]        }    }}
  • domains: lists the domains whose actions may call the connection. No other domain can.
  • environment: is a ProviderEnvironment setting, .sandbox or .live, which picks between the package's hosts. Calls are HTTPS only, and redirects and proxies are always refused.
  • The credential is a secret: true setting (Configuration and time). The package says how it is sent, and code can never read it. For a provider that acts for each user, the credential is an OAuthGrant instead.
  • host: gives the address of a package with no fixed host: another Jadpo app, a self-hosted product, or a service already running elsewhere.
  • timeout: and retry: override the default time limit and retries. max_concurrent: may lower the package's limit on calls at once.
  • webhooks: gives the webhook secret and, for webhooks that need a reply, replies: (see "Receiving from outside", further down this page).
  • polls: changes a poll's interval, outbound: grants a service the hosts its package asks for, erasure: names the field holding the person's key at this provider, and development: lists what reaches the sandbox in jadpo dev. Each has its own section below.
  • A package's own settings: are given by name, such as message_stream: "outbound".

Two versions of one package are two connections, used side by side while callers move across. A library package needs no connection: any domain brings it in with a use line.

Two connections: one to the app's own integration with fixed live and sandbox hosts, and one to an integration with no fixed host, reached at the address a setting gives and taking a setting of its own. The package: line names the package by its name and version, as the lock does, with no use line.

example
application {    connections: {        couriers: {            package: AcmeCouriers.v1            domains: [shipping]            credential: config.couriers_api_key            environment: config.couriers_environment            timeout: 5s        }        ledger: {            package: Ledger.v1            domains: [billing]            credential: config.ledger_token            host: config.ledger_address            account: "shop"        }    }}
example
config {    couriers_api_key: Text {        secret: true    }    couriers_environment: ProviderEnvironment    ledger_address: Url    ledger_token: Text {        secret: true    }}
example
/// The ledger's API, at the address each deployment gives.provider {    protocol: Protocol.json_http    credential: CredentialScheme.bearer    settings: {        account: Text    }}

A package declares its own settings in provider.jadpo's settings:, each a plain value (Text, Int, Decimal, Bool or Duration), and every connection to it gives each one by name, written out or read from a setting of that type (account: config.ledger_account).

A connection's name shares one namespace with the app's domains and libraries, so billing.<name> always means one thing. A connection named like a domain or a library is an error, reported at the connection, because that is the name you can change in app.jadpo without moving any code:

example
application {    connections: {        billing: {            driver: Driver.postgres            url: config.database_url        }    }}
text
error: Connection `billing` is named like domain `billing` --> app.jadpo:3:9  |3 |         billing: {  |         ^^^^^^^ already a domain  reason: Connections share one namespace with domains and libraries, so `billing.<name>` means one thing; it is already the domain `billing`.  next: Rename the connection, such as `billing_api`, and the calls through it (agent)  rule: semantic.duplicate_declaration  help: https://jadpo.dev/docs/errors/semantic.duplicate_declarationcheck failed: 1 error, 4 files

The network report

The network report lists every host your app can reach, so a reviewer sees a new one before it ships. jadpo check writes it to build/report/network.md, with a .json twin, once the connections read cleanly. Each row gives a host, the connection that reaches it, when (a package's environment setting picks its live or sandbox host), what for (a package, or a driver's capability) and the domains that use it.

The report is built for small diffs, as the permissions report is. Rows are in order of connection and host, each host is shown as written, and there are no times or totals. So a new connection or a changed host is a one-line change in review. For the app above:

Connection Host When For Domains
couriers https://api.acme-couriers.example config.couriers_environment is live AcmeCouriers.v1 shipping
couriers https://sandbox.acme-couriers.example config.couriers_environment is sandbox AcmeCouriers.v1 shipping
ledger the address in config.ledger_address always Ledger.v1 billing

A database or cache connection is listed at the address in its url: setting, for the domains whose entities it stores. A database's For says without TLS when its connection says tls: false, and names the setting its server's certificate is checked against when it names an authority: (PostgreSQL over TLS). A store of files on the disk driver reaches no host and isn't listed. A package Jadpo runs (runs:) is listed as the service it runs from its image.

Not built yet: the hosts a service run by Jadpo asks for aren't in the report until services are built.

Markdown for agents: /docs/connecting-in-app-jadpo.md.Built from Jadpo main at a707efb.