--- title: "Cloudflare" description: "Run bknd inside Cloudflare Worker" tags: ["documentation"] --- ## 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: ### CLI Starter Create a new Cloudflare CLI starter project by running the following command: ```sh npx bknd create -i cloudflare ``` ### 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: ```bash tab="npm" npm install bknd ``` ```bash tab="pnpm" pnpm install bknd ``` ```bash tab="yarn" yarn add bknd ``` ```bash tab="bun" bun add bknd ``` ## Serve the API If you don't choose anything specific, it uses the first D1 binding it finds. ```ts title="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({ app: ({ env }) => d1({ binding: env.D1_BINDING }), }); // or specify binding using `bindings` export default serve({ bindings: ({ env }) => ({ db: env.D1_BINDING }), }); // or use LibSQL export default serve({ 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/). ### Assets Make sure your assets point to the static assets included in the bknd package: ```toml title="wrangler.toml" assets = { directory = "node_modules/bknd/dist/static" } ``` ### Workers Sites Make sure your site points to the static assets included in the bknd package: ```toml title="wrangler.toml" [site] bucket = "node_modules/bknd/dist/static" ``` And then modify the worker entry as follows: ```ts title="src/index.ts" import { serve } from "bknd/adapter/cloudflare"; import manifest from "__STATIC_CONTENT_MANIFEST"; // [!code highlight] export default serve({ app: () => ({ /* ... */ }), manifest, // [!code highlight] }); ``` ## Adding custom routes You can also add custom routes by defining them after the app has been built, like so: ```ts import { serve } from "bknd/adapter/cloudflare"; export default serve({ // ... onBuilt: async (app) => { app.server.get("/hello", (c) => c.json({ hello: "world" })); // [!code highlight] }, }); ``` The property `app.server` is a [Hono](https://hono.dev/) instance, you can literally anything you can do with Hono. ## 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 title="src/index.ts" import { serve } from "bknd/adapter/cloudflare"; export default serve({ // ... 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: " ... ``` ## Filesystem access with Vite Plugin The [Cloudflare Vite Plugin](https://developers.cloudflare.com/workers/vite-plugin/) allows to use Vite with Miniflare to emulate the Cloudflare Workers runtime. This is great, however, `unenv` disables any Node.js APIs that aren't supported, including the `fs` module. If you want to use plugins such as [`syncTypes`](/extending/plugins#synctypes), this will cause issues. To fix this, bknd exports a Vite plugin that provides filesystem access during development. You can use it by adding the following to your `vite.config.ts` file: ```ts import { devFsVitePlugin } from "bknd/adapter/cloudflare"; export default defineConfig({ plugins: [devFsVitePlugin()], // [!code highlight] }); ``` Now to use this polyfill, you can use the `devFsWrite` function to write files to the filesystem. ```ts import { devFsWrite } from "bknd/adapter/cloudflare"; // [!code highlight] import { syncTypes } from "bknd/plugins"; export default { options: { plugins: [ syncTypes({ write: async (et) => { await devFsWrite("bknd-types.d.ts", et.toString()); // [!code highlight] } }), ] }, } satisfies BkndConfig; ``` ## Cloudflare Bindings in CLI The bknd CLI does not automatically have access to the Cloudflare bindings. We need to manually proxy them to the CLI by using the `withPlatformProxy` helper function: ```typescript title="bknd.config.ts" import { d1 } from "bknd/adapter/cloudflare"; import { withPlatformProxy } from "bknd/adapter/cloudflare/proxy"; export default withPlatformProxy({ app: ({ env }) => ({ connection: d1({ binding: env.DB }), }), }); ``` Now you can use the CLI with your Cloudflare resources. Make sure to not import from this file in your app, as this would include `wrangler` as a dependency. Instead, it's recommended to split this configuration into separate files, e.g. `bknd.config.ts` and `config.ts`: ```typescript title="config.ts" import type { CloudflareBkndConfig } from "bknd/adapter/cloudflare"; export default { app: ({ env }) => ({ connection: d1({ binding: env.DB }), }), } satisfies CloudflareBkndConfig; ``` `config.ts` now holds the configuration, and can safely be imported in your app. Since the CLI looks for a `bknd.config.ts` file by default, we change it to wrap the configuration from `config.ts` in the `withPlatformProxy` helper function. ```typescript title="bknd.config.ts" import { withPlatformProxy } from "bknd/adapter/cloudflare/proxy"; import config from "./config"; export default withPlatformProxy(config); ``` As an additional safe guard, you have to set a `PROXY` environment variable to `1` to enable the proxy. ```bash PROXY=1 npx bknd types ```