Configuration

There are two parts: enable the extension and allow the binding names Perl may use, then tell Wrangler which resources those names refer to. Merge this webdyne object into your existing package.json:

{
  "webdyne": {
    "extensions": {
      "@webdyne/webdyne-cloudflare": {
        "d1Bindings": ["DB"],
        "kvBindings": ["CACHE"],
        "r2Bindings": ["ASSETS"]
      }
    },
    "cloudflare": {
      "d1Databases": [{
        "binding": "DB",
        "databaseName": "webdyne-time",
        "databaseId": "CLOUDFLARE-DATABASE-ID"
      }],
      "kvNamespaces": [{
        "binding": "CACHE",
        "namespaceId": "CLOUDFLARE-KV-NAMESPACE-ID"
      }],
      "r2Buckets": [{
        "binding": "ASSETS",
        "bucketName": "my-webdyne-assets"
      }]
    }
  }
}

Use only the arrays for services the application needs. The runtime's webdyne-cloudflare command copies the extension's Perl modules to VFS /perl5/lib, statically imports its Cloudflare adapter into the generated Worker, and emits D1, KV, and R2 binding configuration for Wrangler. npm installation itself runs no setup or deployment hooks.

Hyperdrive / PostgreSQL

Enable Hyperdrive and map the binding to an existing configuration:

{
  "webdyne": {
    "extensions": {
      "@webdyne/webdyne-cloudflare": { "hyperdriveBindings": ["DB"] }
    },
    "cloudflare": {
      "hyperdrive": [{ "binding": "DB", "id": "YOUR_32_HEX_HYPERDRIVE_ID" }]
    }
  }
}

Use extension 1.3.0 and runtime 1.0.11 or later, then run webdyne-cloudflare check or deploy. No custom extension manifest or generated Worker edits are needed. D1/KV/R2-only builds retain their original provider. User-owned Wrangler files remain untouched; add the Hyperdrive binding and nodejs_compat yourself in that case. Choose distinct binding names when combining services.

For local development, put the connection string in the private environment variable CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_DB. Do not put credentials in package.json. Use a caching-disabled Hyperdrive configuration when CRUD reads must immediately reflect writes; Hyperdrive does not invalidate cached reads on writes. See Cloudflare local development and query caching.

my $db_or=WebDyne::Cloudflare::Hyperdrive->new(scope => $scope_hr);
my $customer_hr=await $db_or->selectrow_hashref(
    'SELECT id, name FROM customers WHERE id=$1', undef, $customer_id);
await $db_or->disconnect();

The API reference covers transaction callbacks, DBI-style attribute positions, exact types, deadlines and errors. The inventory example includes configuration and sample SQL.

Extension options

Options live in webdyne.extensions["@webdyne/webdyne-cloudflare"]:

| Option | Default | Purpose | | --- | --- | --- | | d1Bindings | No bindings | Array of D1 names Perl may access, such as ["DB"]. | | kvBindings | No bindings | Array of KV names, such as ["CACHE"]. | | r2Bindings | No bindings | Array of R2 names, such as ["OBJECTS"]. | | hyperdriveBindings | No bindings | PostgreSQL/MySQL Hyperdrive binding names. | | secretsStoreBindings | No bindings | Secrets Store binding names. | | durableObjectBindings | No bindings | Durable Object namespaces; generated from object definitions by the CLI. | | durableObjectNativeBindings | No bindings | Namespaces using native JavaScript RPC; also allow them in durableObjectBindings. | | hyperdriveLimits | See API | Connection, row, byte, query and cleanup limits; see Hyperdrive. | | kvMaxValueBytes | 16777216 (16 MiB) | Maximum KV value payload handled by the bridge. | | r2MaxObjectBytes | 16777216 (16 MiB) | Maximum buffered R2 body handled by the bridge. |

Binding names use uppercase letters, digits and underscores, starting with a letter or underscore. Use positive integer byte limits. An explicit empty binding array disables that service, including its compatibility-variable fallback. These options expose existing bindings; they don't create resources.

Resource definitions

These arrays live in webdyne.cloudflare and are translated by the runtime CLI into generated Wrangler configuration:

| Array | Required fields | Optional fields | Wrangler destination | | --- | --- | --- | --- | | d1Databases | binding, databaseName, databaseId | previewDatabaseId | d1_databases: binding, database_name, database_id, preview_database_id | | kvNamespaces | binding | namespaceId, previewNamespaceId, remote | kv_namespaces: binding, id, preview_id, remote | | r2Buckets | binding | bucketName, previewBucketName, jurisdiction, remote | r2_buckets: binding, bucket_name, preview_bucket_name, jurisdiction, remote |

Supply the actual resource identifiers for deployment. KV/R2 allow omitted IDs or names for local development with the bundled Wrangler. remote: true selects real resources during development where supported; omit it for the usual local storage workflow. Provisioning resources and creating a D1 schema are separate from enabling the extension.

If you maintain a root wrangler.jsonc or select one with webdyne.cloudflare.wranglerConfig, the runtime leaves it untouched. Put the resource definitions in that file using Wrangler's names, while keeping the extension allow-lists in package.json. For example, the equivalent binding fragment is:

{
  "d1_databases": [{
    "binding": "DB",
    "database_name": "webdyne-time",
    "database_id": "CLOUDFLARE-DATABASE-ID"
  }],
  "kv_namespaces": [{
    "binding": "CACHE",
    "id": "CLOUDFLARE-KV-NAMESPACE-ID"
  }],
  "r2_buckets": [{
    "binding": "ASSETS",
    "bucket_name": "my-webdyne-assets"
  }]
}

This is a fragment to merge into a working runtime configuration, not a whole Worker config. Keep its entrypoint, module rules, runtime variables and enable_request_signal flag. Rebuild after changing package options or Perl modules. Once local checks pass, use npm run login, npm run whoami and npm run deploy to deploy the configured application.

Additional services

For MySQL, use the same Hyperdrive configuration with a mysql: connection string and ? SQL parameters. PostgreSQL uses $1, $2, and so on. See the MySQL restrictions.

Secrets Store uses secretsStoreBindings and cloudflare.secretsStoreSecrets entries with binding, storeId, and secretName. Generated configuration requires ZeroPerl 1.0.12 or later.

D1 sessions use the normal D1 binding. Enable read replication separately in the database; carry session bookmarks between related requests. Ordinary queries retain primary-only routing.

Durable Objects use cloudflare.durableObjects, plus perlLibrary for application modules. Perl-hosted objects require ZeroPerl 1.0.13 or later. The examples use the qualified 1.0.14 runtime. Generated definitions select the correct namespace allowlists; custom Workers must supply them explicitly.