# Deploy to Cloudflare Workers

`jadpo build` can build your app as WebAssembly for Cloudflare Workers,
with the JavaScript that loads it and the description Wrangler,
Cloudflare's command-line tool, deploys. This guide builds a book
catalogue as a Worker that reaches its PostgreSQL database through
Hyperdrive.

You need:

- **A Cloudflare account.** Check Cloudflare's pricing for which plan
  includes Workers and Hyperdrive.
- **Wrangler.** It needs Node.js; run it with `npx wrangler`, which
  fetches it the first time. `npx wrangler login` opens your browser to
  sign in to Cloudflare.
- **A PostgreSQL database reachable from the internet**, such as one
  from a hosted PostgreSQL provider. One on your own machine won't do,
  since Cloudflare can't reach it.

You start from an app with a `Book` entity and routes that add a book and
read one back. [Build an API](/guides/guide-build-an-api.md) shows how to write those.

## Say what to build

The database's address is a setting, so it isn't written in your code.
`config { }` and `PostgresUrl`, a standard type, are built into Jadpo, and the
name `database_url` is yours.

`config.jadpo`:

```jadpo
config {
    /// The PostgreSQL database the app keeps its data in.
    database_url: PostgresUrl
}
```

`app.jadpo` names the database and the program to build. `main` and `limits` are
names you choose for its two connections, and `web` is a name you choose for the
program. `Driver`, `Target` and `rate_limits:` are built in.

`app.jadpo`:

```jadpo
application {
    connections: {
        main: {
            driver: Driver.postgres
            url: config.database_url
        }
        limits: {
            driver: Driver.cloudflare_rate_limits
            namespace: 1001
        }
    }
    rate_limits: {
        store: limits
    }
    deployables: {
        web: {
            serves: [main]
            target: Target.wasm
        }
    }
}
```

- The `main` connection is your database, read through the `database_url`
  setting.
- `deployables:` lists the programs the app is built into. Without it
  there is one, `app`, built as a server program. `web` is built for
  Workers, `Target.wasm`, and `serves: [main]` means it answers the
  API's routes.
- Every route is rate-limited. A server program counts requests in its
  own memory, but a Worker runs in many places at once, so the counts
  are kept by Cloudflare's rate-limiting binding, through the `limits`
  connection. `namespace: 1001` is a number you choose; Cloudflare needs
  an id for each limit, and Jadpo numbers them from this one.
- An app that sends email or has subscribers or schedules also says the
  Worker runs them: `runs: [Trigger.subscribers, Trigger.schedules]`.

## Build it

```sh
jadpo build
```

```text
  worker: build/target/web/wrangler.json
  module: build/target/web/web.wasm
  size: 7.2 MB, 2.7 MB gzipped
  database: DATABASE_URL through Hyperdrive, no id
  build: b_0ccbb5029fcf
  serves: main
  commit: none
  settings: DATABASE_URL

alert: `DATABASE_URL` has no Hyperdrive id: create one with caching off and build with it in `JADPO_HYPERDRIVE_DATABASE_URL`
alert: Built from files git doesn't track: no commit explains its events

built: web, wasm in 61.7 s

next: jadpo migrate apply  it starts only once its database has every migration
```

`build/target/web/` now holds the Worker: the WebAssembly module, the
JavaScript that loads it, and `wrangler.json`. It names the Worker after
your project's folder and lists the two limits Jadpo counts, numbered
from your `namespace:`. A secret setting with no default would be listed
there too, as one the Worker needs.

## Connect the database through Hyperdrive

A Worker keeps no connection to your database open between requests,
and opening one for each request is slow. Hyperdrive is Cloudflare's
service that keeps connections open and hands one to each request.
Create one for your database with caching off, since a cache could
answer a read with data that has since changed. Keep the database's
address in a file only you can read, such as `~/books-app.env`, holding
`DATABASE_URL=<your database's address>`, and load it from there so it isn't
typed into your shell:

```sh
(set -a; . ~/books-app.env; npx wrangler hyperdrive create books \
  --connection-string="$DATABASE_URL" --caching-disabled)
```

Wrangler prints the new Hyperdrive's id. Build again with it:

```sh
JADPO_HYPERDRIVE_DATABASE_URL=<the id Wrangler printed> jadpo build
```

## Deploy

Apply the migrations to the database first:

```sh
(set -a; . ~/books-app.env; jadpo migrate apply)
```

A hosted provider's address often ends in settings such as
`?sslmode=require`. Remove them: Jadpo refuses an address that sets TLS
itself, since its connection decides, and it always uses TLS to a database
on another machine. Use the provider's direct address, not its pooled one.

Then deploy from the Worker's folder:

```sh
cd build/target/web
npx wrangler deploy
```

On Workers, settings are the Worker's variables and secrets, which
Cloudflare keeps. Store a secret with `npx wrangler secret put <NAME>`,
which asks for the value at a prompt, and give other settings as
`--var NAME:value` to `npx wrangler deploy`. Any setting with no `default:`
is listed as a secret the Worker needs, even one that isn't secret, so
store it with `secret put` too. Wrangler prints the
Worker's address, which answers the same routes and health check as
the server program.

## Read more

[A Workers deployable](/docs/a-workers-deployable.md),
[Declared deployables](/docs/declared-deployables.md)
and [Rate limits on Workers](/docs/rate-limits-on-workers.md).
