API·续

To wrap up a test suite, call await worker.stop() in an afterAll function.

Single Worker example

const { unstable_dev } = require("wrangler");

describe("Worker", () => {
    let worker;

beforeAll(async () => {
        worker = await unstable_dev("src/index.js", {
            experimental: { disableExperimentalWarning: true },
        });
    });

afterAll(async () => {
        await worker.stop();
    });

it("should return Hello World", async () => {
        const resp = await worker.fetch();
        const text = await resp.text();
        expect(text).toMatchInlineSnapshot(`"Hello World!"`);
    });
});
import { unstable_dev } from "wrangler";
import type { UnstableDevWorker } from "wrangler";

describe("Worker", () => {
    let worker: UnstableDevWorker;

beforeAll(async () => {
        worker = await unstable_dev("src/index.ts", {
            experimental: { disableExperimentalWarning: true },
        });
    });

afterAll(async () => {
        await worker.stop();
    });

it("should return Hello World", async () => {
        const resp = await worker.fetch();
        const text = await resp.text();
        expect(text).toMatchInlineSnapshot(`"Hello World!"`);
    });
});

Multi-Worker example

You can test Workers that call other Workers. In the below example, we refer to the Worker that calls other Workers as the parent Worker, and the Worker being called as a child Worker.

If you shut down the child Worker prematurely, the parent Worker will not know the child Worker exists and your tests will fail.

import { unstable_dev } from "wrangler";

describe("multi-worker testing", () => {
    let childWorker;
    let parentWorker;

beforeAll(async () => {
        childWorker = await unstable_dev("src/child-worker.js", {
            config: "src/child-wrangler.toml",
            experimental: { disableExperimentalWarning: true },
        });
        parentWorker = await unstable_dev("src/parent-worker.js", {
            config: "src/parent-wrangler.toml",
            experimental: { disableExperimentalWarning: true },
        });
    });

afterAll(async () => {
        await childWorker.stop();
        await parentWorker.stop();
    });

it("childWorker should return Hello World itself", async () => {
        const resp = await childWorker.fetch();
        const text = await resp.text();
        expect(text).toMatchInlineSnapshot(`"Hello World!"`);
    });

it("parentWorker should return Hello World by invoking the child worker", async () => {
        const resp = await parentWorker.fetch();
        const parsedResp = await resp.text();
        expect(parsedResp).toEqual("Parent worker sees: Hello World!");
    });
});
import { unstable_dev } from "wrangler";
import type { UnstableDevWorker } from "wrangler";

describe("multi-worker testing", () => {
    let childWorker: UnstableDevWorker;
    let parentWorker: UnstableDevWorker;

beforeAll(async () => {
        childWorker = await unstable_dev("src/child-worker.js", {
            config: "src/child-wrangler.toml",
            experimental: { disableExperimentalWarning: true },
        });
        parentWorker = await unstable_dev("src/parent-worker.js", {
            config: "src/parent-wrangler.toml",
            experimental: { disableExperimentalWarning: true },
        });
    });

afterAll(async () => {
        await childWorker.stop();
        await parentWorker.stop();
    });

it("childWorker should return Hello World itself", async () => {
        const resp = await childWorker.fetch();
        const text = await resp.text();
        expect(text).toMatchInlineSnapshot(`"Hello World!"`);
    });

it("parentWorker should return Hello World by invoking the child worker", async () => {
        const resp = await parentWorker.fetch();
        const parsedResp = await resp.text();
        expect(parsedResp).toEqual("Parent worker sees: Hello World!");
    });
});

getPlatformProxy

The getPlatformProxy function provides a way to obtain an object containing proxies (to local workerd bindings) and emulations of Cloudflare Workers specific values, allowing the emulation of such in a Node.js process.

Caution

getPlatformProxy is, by design, to be used exclusively in Node.js applications. getPlatformProxy cannot be run inside the Workers runtime.

One general use case for getting a platform proxy is for emulating bindings in applications targeting Workers, but running outside the Workers runtime (for example, framework local development servers running in Node.js), or for testing purposes (for example, ensuring code properly interacts with a type of binding).

Note

Binding proxies provided by this function are a best effort emulation of the real production bindings. Although they are designed to be as close as possible to the real thing, there might be slight differences and inconsistencies between the two.

Syntax

const platform = await getPlatformProxy(options);

Parameters

  • options object optional
  • Optional options object containing preferences for the bindings:
    • environment string

The environment to use. - configPath string

The path to the config file to use.

If no path is specified, the default behavior is to search from the current directory up the filesystem for a Wrangler configuration file to use.

Note: this field is optional but if a path is specified it must point to a valid file on the filesystem. - persist boolean | { path: string }

Indicates if and where to persist the bindings data. If true or undefined, defaults to the same location used by Wrangler, so data can be shared between it and the caller. If false, no data is persisted to or read from the filesystem.

Note: If you use wrangler's --persist-to option, note that this option adds a subdirectory called v3 under the hood while getPlatformProxy's persist does not. For example, if you run wrangler dev --persist-to ./my-directory, to reuse the same location using getPlatformProxy, you will have to specify: persist: { path: "./my-directory/v3" }. - remoteBindings boolean optional (default: `true`)

Whether or not remote bindings should be enabled.

Return Type

getPlatformProxy() returns a Promise resolving to an object containing the following fields.

  • env Record<string, unknown>
  • Object containing proxies to bindings that can be used in the same way as production bindings. This matches the shape of the env object passed as the second argument to modules-format workers. These proxy to binding implementations run inside workerd.
  • TypeScript Tip: getPlatformProxy<Env>() is a generic function. You can pass the shape of the bindings record as a type argument to get proper types without unknown values.
  • cf IncomingRequestCfProperties read-only
  • Mock of the Request's cf property, containing data similar to what you would see in production.
  • ctx object
  • Mock object containing implementations of the waitUntil and passThroughOnException functions that do nothing.
  • caches object
  • Emulation of the Workers caches runtime API.
  • For the time being, all cache operations do nothing. A more accurate emulation will be made available soon.
  • dispose() () => Promise<void>
  • Terminates the underlying workerd process.
  • Call this after the platform proxy is no longer required by the program. If you are running a long running process (such as a dev server) that can indefinitely make use of the proxy, you do not need to call this function.

Usage

The getPlatformProxy function uses bindings found in the Wrangler configuration file. For example, if you have an environment variable configuration set up in the Wrangler configuration file:

{
    "vars": {
        "MY_VARIABLE": "test"
    }
}
[vars]
MY_VARIABLE = "test"

You can access the bindings by importing getPlatformProxy like this:

import { getPlatformProxy } from "wrangler";

const { env } = await getPlatformProxy();

To access the value of the MY_VARIABLE binding add the following to your code:

console.log(`MY_VARIABLE = ${env.MY_VARIABLE}`);

This will print the following output: MY_VARIABLE = test.

Supported bindings

All supported bindings found in your Wrangler configuration file are available to you via env.

getPlatformProxy does not run your Worker's code. It ignores the Workflows declared in the exports field of your Wrangler configuration.

The bindings supported by getPlatformProxy are:

Hyperdrive values are simple passthrough ones

Values provided by hyperdrive bindings such as connectionString and host do not have a valid meaning outside of a workerd process. This means that Hyperdrive proxies return passthrough values, which are values corresponding to the database connection provided by the user. Otherwise, it would return values which would be unusable from within node.js. - Workers AI bindings

Workers AI local development usage charges

Using Workers AI always accesses your Cloudflare account in order to run AI models and will incur usage charges even in local development. - Durable Object bindings - To use a Durable Object binding with getPlatformProxy, always specify a script_name.

For example, you might have the following binding in a Wrangler configuration file read by getPlatformProxy.

    {
      "durable_objects": {
        "bindings": [
          {
            "name": "MyDurableObject",
            "class_name": "MyDurableObject",
            "script_name": "external-do-worker"
          }
        ]
      }
    }
    ```

```toml
    [[durable_objects.bindings]]
    name = "MyDurableObject"
    class_name = "MyDurableObject"
    script_name = "external-do-worker"
    ```

You will need to declare your Durable Object `"MyDurableObject"` in another Worker, called `external-do-worker` in this example.

*./external-do-worker/src/index.tsts*

```ts
    export class MyDurableObject extends DurableObject {
        // Your DO code goes here
    }

export default {
        fetch() {
            // Doesn't have to do anything, but a DO cannot be the default export
            return new Response("Hello, world!");
        },
    };
    ```

That Worker also needs a Wrangler configuration file that looks like this:

```jsonc
    {
        "name": "external-do-worker",
        "main": "src/index.ts",
        "upload_source_maps": true,
        "compatibility_date": "XXXX-XX-XX"
    }
    ```

```toml
    name = "external-do-worker"
    main = "src/index.ts"
    upload_source_maps = true
    compatibility_date = "XXXX-XX-XX"
    ```

If you are not using RPC with your Durable Object, you can run a separate Wrangler dev session alongside your framework development server.

Otherwise, you can build your application and run both Workers in the same Wrangler dev session.

If you are using Pages run:npmyarnpnpm

npx wrangler pages dev -c path/to/pages/wrangler.jsonc -c path/to/external-do-worker/wrangler.jsonc
```
    yarn wrangler pages dev -c path/to/pages/wrangler.jsonc -c path/to/external-do-worker/wrangler.jsonc
    ```

pnpm wrangler pages dev -c path/to/pages/wrangler.jsonc -c path/to/external-do-worker/wrangler.jsonc
```

If you are using Workers with Assets run:npmyarnpnpm

    npx wrangler dev -c path/to/workers-assets/wrangler.jsonc -c path/to/external-do-worker/wrangler.jsonc
    ```

yarn wrangler dev -c path/to/workers-assets/wrangler.jsonc -c path/to/external-do-worker/wrangler.jsonc
```
    pnpm wrangler dev -c path/to/workers-assets/wrangler.jsonc -c path/to/external-do-worker/wrangler.jsonc
    ```

Was this helpful?

YesNo

## On this page

[![](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NiIgaGVpZ2h0PSIzMCIgZmlsbD0ibm9uZSIgdmlld0JveD0iMCAwIDY2IDMwIj48ZyBjbGlwLXBhdGg9InVybCgjY2xpcDBfNzQ2XzIpIj48cGF0aCBmaWxsPSIjZmY5OTEwIiBkPSJNNTMuMTIgMTMuMTI1YzYuOTk3IDAgMTIuNjY4IDUuNzA4IDEyLjY2OCAxMi43NSAwIDEuMjU1LS4xOCAyLjQ2OC0uNTE2IDMuNjE0YS43Mi43MiAwIDAgMS0uNjk0LjUxMUg0Ni45NTNhLjM3NS4zNzUgMCAwIDEtLjM0OC0uNTFsLjMzNy0uODgyYzEuMDc2LTIuODMzIDQuMTQ2LTUuMTU0IDYuOTg3LTUuMjlsNS4zODQtLjI3N2EuNTQzLjU0MyAwIDAgMCAuNTE0LS41NDQuNTQzLjU0MyAwIDAgMC0uNTEtLjU0NGwtNS4wNTYtLjI5OWMtMi43MTgtLjE0LTQuMDQ2LTIuNTYtMy4zMTUtNS4wODFsLjg0Mi0yLjkwMmEuNzIuNzIgMCAwIDEgLjY0Ni0uNTI3cS4zNC0uMDIuNjg2LS4wMTkiLz48cGF0aCBmaWxsPSIjZmY1ZjA4IiBkPSJNMzUuNjA5IDBjNy4yOTUgMCAxMy40MjQgNS4wMjUgMTUuMTU3IDExLjgyNC4wNzMuMjg1LjA1LjU4Ni0uMDU0Ljg2MmwtMS4zODggMy42NzdjLTEuMDc2IDIuODMzLTMuODQyIDUuMjktNi45NyA1LjI5bC0yNC4xMDUuMjc4YS41MzMuNTMzIDAgMCAwLS41MjUuNTM1YzAgLjI5My4yMzQuNTMxLjUyNC41MzVsMjMuNzY1LjMxNmMyLjcyNCAwIDQuMDQ2IDIuNTYgMy4zMTYgNS4wODFsLS4zMDcgMS4wNjFhLjc1Ljc1IDAgMCAxLS43MTYuNTQxSC45NjRhLjcxLjcxIDAgMCAxLS43MTgtLjY0NiAxMSAxMSAwIDAgMS0uMDM0LS44NTRjMC01LjQ3NiA0LjE2Ni05Ljk3MyA5LjQ4Mi0xMC40NTZhNy4yIDcuMiAwIDAgMS0uMTY3LTEuNTQ0YzAtMy45MzUgMy4xNy03LjEyNSA3LjA4LTcuMTI1IDEuNTU1IDAgMi45OTQuNTA2IDQuMTYyIDEuMzYyQzIyLjg0OSA0LjQ5NyAyOC43MDcgMCAzNS42MDkgMCIvPjxwYXRoIGZpbGw9IiNmZjk5MTAiIGQ9Ik01My4xMiAxMy4xMjVjNi45OTcgMCAxMi42NjggNS43MDggMTIuNjY4IDEyLjc1IDAgMS4yNTUtLjE4IDIuNDY4LS41MTYgMy42MTRhLjcyLjcyIDAgMCAxLS42OTQuNTExSDQ2Ljk1M2EuMzc1LjM3NSAwIDAgMS0uMzQ4LS41MWwuMzM3LS44ODJjMS4wNzYtMi44MzMgNC4xNDYtNS4xNTQgNi45ODctNS4yOWw1LjM4NC0uMjc3YS41NDMuNTQzIDAgMCAwIC41MTQtLjU0NC41NDMuNTQzIDAgMCAwLS41MS0uNTQ0bC01LjA1Ni0uMjk5Yy0yLjcxOC0uMTQtNC4wNDYtMi41Ni0zLjMxNS01LjA4MWwuODQyLTIuOTAyYS43Mi43MiAwIDAgMSAuNjQ2LS41MjdxLjM0LS4wMi42ODYtLjAxOSIvPjxwYXRoIGZpbGw9IiNmZjVmMDgiIGQ9Ik0zNS42MDkgMGM3LjI5NSAwIDEzLjQyNCA1LjAyNSAxNS4xNTcgMTEuODI0LjA3My4yODUuMDUuNTg2LS4wNTQuODYybC0xLjM4OCAzLjY3N2MtMS4wNzYgMi44MzMtMy44NDIgNS4yOS02Ljk3IDUuMjlsLTI0LjEwNS4yNzhhLjUzMy41MzMgMCAwIDAtLjUyNS41MzVjMCAuMjkzLjIzNC41MzEuNTI0LjUzNWwyMy43NjUuMzE2YzIuNzI0IDAgNC4wNDYgMi41NiAzLjMxNiA1LjA4MWwtLjMwNyAxLjA2MWEuNzUuNzUgMCAwIDEtLjcxNi41NDFILjk2NGEuNzEuNzEgMCAwIDEtLjcxOC0uNjQ2IDExIDExIDAgMCAxLS4wMzQtLjg1NGMwLTUuNDc2IDQuMTY2LTkuOTczIDkuNDgyLTEwLjQ1NmE3LjIgNy4yIDAgMCAxLS4xNjctMS41NDRjMC0zLjkzNSAzLjE3LTcuMTI1IDcuMDgtNy4xMjUgMS41NTUgMCAyLjk5NC41MDYgNC4xNjIgMS4zNjJDMjIuODQ5IDQuNDk3IDI4LjcwNyAwIDM1LjYwOSAwIi8+PC9nPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDBfNzQ2XzIiPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik0wIDBoNjZ2MzBIMHoiLz48L2NsaXBQYXRoPjwvZGVmcz48L3N2Zz4=)Docs](https://developers.cloudflare.com/)

```json
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/workers/wrangler/api/#page","headline":"API","description":"A set of programmatic APIs that can be integrated with local Cloudflare Workers-related workflows.","url":"https://developers.cloudflare.com/workers/wrangler/api/","inLanguage":"en","image":"https://developers.cloudflare.com/workers/wrangler/api/og.png?v=c08a17f641408034","dateModified":"2026-10-12","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}


description: Resolve common Cloudflare API token issues including verification failures, incorrect permissions, and syntax errors. title: Troubleshooting image: https://developers.cloudflare.com/fundamentals/api/troubleshooting/og.png?v=950d5df516e7dcb8


Skip to content

Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/fundamentals/llms.txt
Use this file to discover all available pages before exploring further.