mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 20:37:21 +00:00
238 lines
8.4 KiB
Plaintext
238 lines
8.4 KiB
Plaintext
---
|
|
title: 'Cloudflare'
|
|
description: 'Run bknd inside Cloudflare Worker'
|
|
---
|
|
import InstallBknd from '/snippets/install-bknd.mdx';
|
|
|
|
## Installation
|
|
To get started with Cloudflare Workers and bknd you can either install the package manually, and follow the descriptions below, or use the CLI starter:
|
|
|
|
<Tabs>
|
|
<Tab title="CLI Starter">
|
|
Create a new Cloudflare CLI starter project by running the following command:
|
|
|
|
```sh
|
|
npx bknd create -i cloudflare
|
|
```
|
|
</Tab>
|
|
<Tab title="Manual">
|
|
Create a new cloudflare worker project by following the [official guide](https://developers.cloudflare.com/workers/get-started/guide/), and then install bknd as a dependency:
|
|
|
|
<InstallBknd />
|
|
</Tab>
|
|
</Tabs>
|
|
|
|
|
|
## Serve the API
|
|
If you don't choose anything specific, the following code will use the `warm` mode and uses the first D1 binding it finds. See the
|
|
chapter [Using a different mode](#using-a-different-mode) for available modes.
|
|
|
|
```ts src/index.ts
|
|
import { serve, d1 } from "bknd/adapter/cloudflare";
|
|
|
|
// scans your environment for the first D1 binding it finds
|
|
export default serve();
|
|
|
|
// manually specifying a D1 binding:
|
|
export default serve<Env>({
|
|
app: ({ env }) => d1({ binding: env.D1_BINDING })
|
|
});
|
|
|
|
// or specify binding using `bindings`
|
|
export default serve<Env>({
|
|
bindings: ({ env }) => ({ db: env.D1_BINDING })
|
|
});
|
|
|
|
// or use LibSQL
|
|
export default serve<Env>({
|
|
app: ({ env }) => ({ url: env.DB_URL })
|
|
});
|
|
```
|
|
|
|
For more information about the connection object when using LibSQL, refer to the [Database](/usage/database) guide.
|
|
|
|
Now run the worker:
|
|
```bash
|
|
wrangler dev
|
|
```
|
|
|
|
And confirm it works by opening [http://localhost:8787](http://localhost:8787) in
|
|
your browser.
|
|
|
|
## Serve the Admin UI
|
|
Now in order to also server the static admin files, you have to modify the `wrangler.toml` to include the static assets. You can do so by either serving the static using the new [Assets feature](https://developers.cloudflare.com/workers/static-assets/), or the deprecated [Workers Site](https://developers.cloudflare.com/workers/configuration/sites/configuration/).
|
|
|
|
<Tabs>
|
|
<Tab title="Assets">
|
|
Make sure your assets point to the static assets included in the bknd package:
|
|
|
|
```toml wrangler.toml
|
|
assets = { directory = "node_modules/bknd/dist/static" }
|
|
```
|
|
|
|
</Tab>
|
|
<Tab title="Workers Sites">
|
|
Make sure your site points to the static assets included in the bknd package:
|
|
|
|
```toml wrangler.toml
|
|
[site]
|
|
bucket = "node_modules/bknd/dist/static"
|
|
```
|
|
|
|
And then modify the worker entry as follows:
|
|
```ts {2, 6} src/index.ts
|
|
import { serve } from "bknd/adapter/cloudflare";
|
|
import manifest from "__STATIC_CONTENT_MANIFEST";
|
|
|
|
export default serve<Env>({
|
|
app: () => ({/* ... */}),
|
|
manifest
|
|
});
|
|
```
|
|
</Tab>
|
|
</Tabs>
|
|
|
|
## Adding custom routes
|
|
You can also add custom routes by defining them after the app has been built, like so:
|
|
```ts {5-7}
|
|
import { serve } from "bknd/adapter/cloudflare";
|
|
|
|
export default serve<Env>({
|
|
// ...
|
|
onBuilt: async (app) => {
|
|
app.server.get("/hello", (c) => c.json({ hello: "world" }));
|
|
}
|
|
});
|
|
```
|
|
The property `app.server` is a [Hono](https://hono.dev/) instance, you can literally anything you can do with Hono.
|
|
|
|
## Using a different mode
|
|
With the Cloudflare Workers adapter, you're being offered to 4 modes to choose from (default:
|
|
`warm`):
|
|
|
|
| Mode | Description | Use Case |
|
|
|:----------|:-------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------|
|
|
| `fresh` | On every request, the configuration gets refetched, app built and then served. | Ideal if you don't want to deal with eviction, KV or Durable Objects. |
|
|
| `warm` | It tries to keep the built app in memory for as long as possible, and rebuilds if evicted. | Better response times, should be the default choice. |
|
|
| `cache` | The configuration is fetched from KV to reduce the initial roundtrip to the database. | Generally faster response times with irregular access patterns. |
|
|
| `durable` | The bknd app is ran inside a Durable Object and can be configured to stay alive. | Slowest boot time, but fastest responses. Can be kept alive for as long as you want, giving similar response times as server instances. |
|
|
|
|
### Modes: `fresh` and `warm`
|
|
To use either `fresh` or `warm`, all you have to do is adding the desired mode to `cloudflare.
|
|
mode`, like so:
|
|
```ts
|
|
import { serve } from "bknd/adapter/cloudflare";
|
|
|
|
export default serve({
|
|
// ...
|
|
mode: "fresh" // mode: "fresh" | "warm" | "cache" | "durable"
|
|
});
|
|
```
|
|
|
|
### Mode: `cache`
|
|
For the cache mode to work, you also need to specify the KV to be used. For this, use the
|
|
`bindings` property:
|
|
|
|
```ts
|
|
import { serve } from "bknd/adapter/cloudflare";
|
|
|
|
export default serve<Env>({
|
|
// ...
|
|
mode: "cache",
|
|
bindings: ({ env }) => ({ kv: env.KV })
|
|
});
|
|
```
|
|
|
|
### Mode: `durable` (advanced)
|
|
To use the `durable` mode, you have to specify the Durable Object to extract from your
|
|
environment, and additionally export the `DurableBkndApp` class:
|
|
```ts
|
|
import { serve, DurableBkndApp } from "bknd/adapter/cloudflare";
|
|
|
|
export { DurableBkndApp };
|
|
export default serve<Env>({
|
|
// ...
|
|
mode: "durable",
|
|
bindings: ({ env }) => ({ dobj: env.DOBJ }),
|
|
keepAliveSeconds: 60 // optional
|
|
});
|
|
```
|
|
|
|
Next, you need to define the Durable Object in your `wrangler.toml` file (refer to the [Durable
|
|
Objects](https://developers.cloudflare.com/durable-objects/) documentation):
|
|
```toml
|
|
[[durable_objects.bindings]]
|
|
name = "DOBJ"
|
|
class_name = "DurableBkndApp"
|
|
|
|
[[migrations]]
|
|
tag = "v1"
|
|
new_classes = ["DurableBkndApp"]
|
|
```
|
|
|
|
Since the communication between the Worker and Durable Object is serialized, the `onBuilt`
|
|
property won't work. To use it (e.g. to specify special routes), you need to extend from the
|
|
`DurableBkndApp`:
|
|
```ts
|
|
import type { App } from "bknd";
|
|
import { serve, DurableBkndApp } from "bknd/adapter/cloudflare";
|
|
|
|
export default serve({
|
|
// ...
|
|
mode: "durable",
|
|
bindings: ({ env }) => ({ dobj: env.DOBJ }),
|
|
keepAliveSeconds: 60 // optional
|
|
});
|
|
|
|
export class CustomDurableBkndApp extends DurableBkndApp {
|
|
async onBuilt(app: App) {
|
|
app.modules.server.get("/custom/endpoint", (c) => c.text("Custom"));
|
|
}
|
|
}
|
|
```
|
|
In case you've already deployed your Worker, the deploy command may complain about a new class
|
|
being used. To fix this issue, you need to add a "rename migration":
|
|
```toml
|
|
[[durable_objects.bindings]]
|
|
name = "DOBJ"
|
|
class_name = "CustomDurableBkndApp"
|
|
|
|
[[migrations]]
|
|
tag = "v1"
|
|
new_classes = ["DurableBkndApp"]
|
|
|
|
[[migrations]]
|
|
tag = "v2"
|
|
renamed_classes = [{from = "DurableBkndApp", to = "CustomDurableBkndApp"}]
|
|
deleted_classes = ["DurableBkndApp"]
|
|
```
|
|
|
|
## D1 Sessions (experimental)
|
|
D1 now supports to enable [global read replication](https://developers.cloudflare.com/d1/best-practices/read-replication/). This allows to reduce latency by reading from the closest region. In order for this to work, D1 has to be started from a bookmark. You can enable this behavior on bknd by setting the `d1.session` property:
|
|
|
|
```typescript src/index.ts
|
|
import { serve } from "bknd/adapter/cloudflare";
|
|
|
|
export default serve({
|
|
// currently recommended to use "fresh" mode
|
|
// otherwise consecutive requests will use the same bookmark
|
|
mode: "fresh",
|
|
// ...
|
|
d1: {
|
|
// enables D1 sessions
|
|
session: true,
|
|
// (optional) restrict the transport, options: "header" | "cookie"
|
|
// if not specified, it supports both
|
|
transport: "cookie",
|
|
// (optional) choose session constraint if not bookmark present
|
|
// options: "first-primary" | "first-unconstrained"
|
|
first: "first-primary"
|
|
}
|
|
});
|
|
```
|
|
|
|
If bknd is used in a stateful user context (like in a browser), it'll automatically send the session cookie to the server to set the correct bookmark. If you need to manually set the bookmark, you can do so by setting the `x-cf-d1-session` header:
|
|
|
|
```bash
|
|
curl -H "x-cf-d1-session: <bookmark>" ...
|
|
``` |