Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added img/cloudflare-integration/add-binding.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cloudflare-integration/redis-add-binding.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cloudflare-integration/redis-secrets.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cloudflare-integration/secrets-store.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cloudflare-integration/secrets.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
152 changes: 85 additions & 67 deletions qstash/quickstarts/cloudflare-workers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,24 @@ This will install the `create-cloudflare` package, and lead you through setup. C
```text
➜ npm create cloudflare@latest
Need to install the following packages:
create-cloudflare@2.1.0
create-cloudflare@2.52.3
Ok to proceed? (y) y

using create-cloudflare version 2.1.0
using create-cloudflare version 2.52.3

╭ Create an application with Cloudflare Step 1 of 3
├ In which directory do you want to create your application?
│ dir ./cloudflare_starter
├ What type of application do you want to create?
type "Hello World" Worker
├ What would you like to start with?
category Hello World example
Do you want to use TypeScript?
yes typescript
Which template would you like to use?
type Worker only
├ Copying files from "hello-world" template
├ Do you want to use TypeScript?
│ yes typescript
├ Retrieving current workerd compatibility date
│ compatibility date 2023-08-07
├ Which language do you want to use?
│ lang TypeScript
├ Do you want to use git for version control?
│ yes git
Expand All @@ -67,16 +62,16 @@ npm install @upstash/qstash
First we import the library:

```ts src/index.ts
import { Receiver } from "@upstash/qstash"
import { Receiver } from "@upstash/qstash";
```

Then we adjust the `Env` interface to include the `QSTASH_CURRENT_SIGNING_KEY`
and `QSTASH_NEXT_SIGNING_KEY` environment variables.

```ts src/index.ts
export interface Env {
QSTASH_CURRENT_SIGNING_KEY: string
QSTASH_NEXT_SIGNING_KEY: string
QSTASH_CURRENT_SIGNING_KEY: string;
QSTASH_NEXT_SIGNING_KEY: string;
}
```

Expand All @@ -88,98 +83,122 @@ First we create a new receiver and provide it with the signing keys.
const receiver = new Receiver({
currentSigningKey: env.QSTASH_CURRENT_SIGNING_KEY,
nextSigningKey: env.QSTASH_NEXT_SIGNING_KEY,
})
});
```

Then we verify the signature.

```ts src/index.ts
const body = await request.text()
const body = await request.text();

const isValid = await receiver.verify({
signature: request.headers.get("Upstash-Signature")!,
body,
})
});
```

The entire file looks like this now:

```ts src/index.ts
import { Receiver } from "@upstash/qstash"
import { Receiver } from "@upstash/qstash";

export interface Env {
QSTASH_CURRENT_SIGNING_KEY: string
QSTASH_NEXT_SIGNING_KEY: string
QSTASH_CURRENT_SIGNING_KEY: string;
QSTASH_NEXT_SIGNING_KEY: string;
}

export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const c = new Receiver({
async fetch(request, env, ctx): Promise<Response> {
const receiver = new Receiver({
currentSigningKey: env.QSTASH_CURRENT_SIGNING_KEY,
nextSigningKey: env.QSTASH_NEXT_SIGNING_KEY,
})
});

const body = await request.text()
const body = await request.text();

const isValid = await c
.verify({
signature: request.headers.get("Upstash-Signature")!,
body,
})
.catch((err) => {
console.error(err)
return false
})
const isValid = await receiver.verify({
signature: request.headers.get("Upstash-Signature")!,
body,
});

if (!isValid) {
return new Response("Invalid signature", { status: 401 })
return new Response("Invalid signature", { status: 401 });
}

// signature is valid

return new Response("Hello World!")
return new Response("Hello World!");
},
}
} satisfies ExportedHandler<Env>;
```

### Configure Credentials

There are two methods for setting up the credentials for QStash. The recommended way is to use Cloudflare Upstash Integration. Alternatively, you can add the credentials manually.
There are two methods for setting up the credentials for QStash. One for worker level, the other for account level.

#### Using the Cloudflare Integration
#### Using Cloudflare Secrets (Worker Level Secrets)

Access to the [Cloudflare Dashboard](https://dash.cloudflare.com) and login with the same account that you've used while setting up the Worker application. Then, navigate to **Workers & Pages > Overview** section on the sidebar. Here, you'll find your application listed.
This is the common way of creating secrets for your worker, see [Workflow Secrets](https://developers.cloudflare.com/workers/configuration/secrets/)

<Frame>
<img src="/img/cloudflare-integration/overview.png" />
</Frame>
- Navigate to [Upstash Console](https://console.upstash.com) and get your QStash credentials.

Clicking on the application will direct you to the application details page, where you can perform the integration process. Switch to the **Settings** tab in the application details, and proceed to **Integrations** section. You will see various Worker integrations listed. To proceed, click the **Add Integration** button associated with the QStash.
- In [Cloudflare Dashboard](https://dash.cloudflare.com/), Go to **Compute (Workers)** > **Workers & Pages**.

<Frame>
<img src="/img/cloudflare-integration/qstash-add-integration.png" />
</Frame>
- Select your worker and go to **Settings** > **Variables and Secrets**.

On the Integration page, connect to your Upstash account. Then, select the related database from the dropdown menu. Finalize the process by pressing Save button.
- Add your QStash credentials as secrets here:

<Frame>
<img src="/img/cloudflare-integration/qstash-credentials.png" />
<img src="/img/cloudflare-integration/secrets.png" />
</Frame>

#### Setting up Manually
#### Using Cloudflare Secrets Store (Account Level Secrets)

This method requires a few modifications in the worker code, see [Access to Secret on Env Object](https://developers.cloudflare.com/secrets-store/integrations/workers/#3-access-the-secret-on-the-env-object)

Navigate to [Upstash Console](https://console.upstash.com) and copy/paste your QStash credentials to `wrangler.toml` as below.
```ts src/index.ts
import { Receiver } from "@upstash/qstash";

```yaml
[vars]
QSTASH_URL="REPLACE_HERE"
QSTASH_TOKEN="REPLACE_HERE"
QSTASH_CURRENT_SIGNING_KEY="REPLACE_HERE"
QSTASH_NEXT_SIGNING_KEY="REPLACE_HERE"
export interface Env {
QSTASH_CURRENT_SIGNING_KEY: SecretsStoreSecret;
QSTASH_NEXT_SIGNING_KEY: SecretsStoreSecret;
}

export default {
async fetch(request, env, ctx): Promise<Response> {
const c = new Receiver({
currentSigningKey: await env.QSTASH_CURRENT_SIGNING_KEY.get(),
nextSigningKey: await env.QSTASH_NEXT_SIGNING_KEY.get(),
});

// Rest of the code
},
};
```

### Test and Deploy
After doing these modifications, you can deploy the worker to Cloudflare with `npx wrangler deploy`, and
follow the steps below to define the secrets:

- Navigate to [Upstash Console](https://console.upstash.com) and get your QStash credentials.

- In [Cloudflare Dashboard](https://dash.cloudflare.com/), Go to **Secrets Store** and add QStash credentials as secrets.

<Frame>
<img src="/img/cloudflare-integration/secrets-store.png" />
</Frame>

- Under **Compute (Workers)** > **Workers & Pages**, find your worker and add these secrets as bindings.

You can test the function locally with `npx wrangler dev`
<Frame>
<img src="/img/cloudflare-integration/add-binding.png" />
</Frame>

### Deployment

<Note>
Newer deployments may revert the configurations you did in the dashboard.
While worker level secrets persist, the bindings will be gone!
</Note>

Deploy your function to Cloudflare with `npx wrangler deploy`

Expand All @@ -191,7 +210,7 @@ Open a different terminal and publish a message to QStash. Note the destination
url is the same that was printed in the previous deploy step.

```bash
curl --request POST "https://qstash.upstash.io/v2/publish/https://cloudflare-workers.upstash.workers.dev" \
curl --request POST "https://qstash.upstash.io/v2/publish/https://<your-worker-name>.<account-name>.workers.dev" \
-H "Authorization: Bearer <QSTASH_TOKEN>" \
-H "Content-Type: application/json" \
-d "{ \"hello\": \"world\"}"
Expand All @@ -202,13 +221,12 @@ In the logs you should see something like this:
```bash
$ npx wrangler tail

⛅️ wrangler 2.0.17
⛅️ wrangler 4.43.0
--------------------
Retrieving cached values for account from node_modules/.cache/wrangler
Successfully created tail, expires at 2022-07-11T21:11:36Z
Connected to cloudflare-workers, waiting for logs...
POST https://cloudflare-workers.upstash.workers.dev/ - Ok @ 7/11/2022, 5:13:19 PM
(log) The signature was valid

Successfully created tail, expires at 2025-10-16T00:25:17Z
Connected to <your-worker-name>, waiting for logs...
POST https://<your-worker-name>.<account-name>.workers.dev/ - Ok @ 10/15/2025, 10:34:55 PM
```

## Next Steps
Expand Down
118 changes: 92 additions & 26 deletions redis/quickstarts/cloudflareworkers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,14 @@ export interface Env {
}

export default {
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext
): Promise<Response> {
const redis = Redis.fromEnv(env);
const count = await redis.incr("counter");
return new Response(JSON.stringify({ count }));
},
};
async fetch(request, env, ctx): Promise<Response> {
const redis = Redis.fromEnv(env);
const count = await redis.incr("counter");
return new Response(JSON.stringify({ count }));

},
} satisfies ExportedHandler<Env>;

```

```js src/index.js
Expand All @@ -124,34 +122,102 @@ export default {

### Configure Credentials

Navigate to [Upstash Console](https://console.upstash.com) and copy/paste your `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN` to your `wrangler.toml` as below.
There are two methods for setting up the credentials for Redis. One for worker level, the other for account level.

<CodeGroup>
#### Using Cloudflare Secrets (Worker Level Secrets)

```yaml wrangler.toml
[vars]
UPSTASH_REDIS_REST_URL="REPLACE_HERE"
UPSTASH_REDIS_REST_TOKEN="REPLACE_HERE"
```
```jsonc wrangler.jsonc
{
"vars": {
"UPSTASH_REDIS_REST_URL": "REPLACE_HERE",
"UPSTASH_REDIS_REST_TOKEN": "REPLACE_HERE"
}
This is the common way of creating secrets for your worker, see [Workflow Secrets](https://developers.cloudflare.com/workers/configuration/secrets/)

- Navigate to [Upstash Console](https://console.upstash.com) and get your Redis credentials.

- In [Cloudflare Dashboard](https://dash.cloudflare.com/), Go to **Compute (Workers)** > **Workers & Pages**.

- Select your worker and go to **Settings** > **Variables and Secrets**.

- Add your Redis credentials as secrets here:

<Frame>
<img src="/img/cloudflare-integration/redis-secrets.png" />
</Frame>

#### Using Cloudflare Secrets Store (Account Level Secrets)

This method requires a few modifications in the worker code, see [Access to Secret on Env Object](https://developers.cloudflare.com/secrets-store/integrations/workers/#3-access-the-secret-on-the-env-object)

```ts src/index.ts
import { Redis } from "@upstash/redis/cloudflare";

export interface Env {
UPSTASH_REDIS_REST_URL: SecretsStoreSecret;
UPSTASH_REDIS_REST_TOKEN: SecretsStoreSecret;
}

export default {
async fetch(request, env, ctx): Promise<Response> {
const redis = Redis.fromEnv({
UPSTASH_REDIS_REST_URL: await env.UPSTASH_REDIS_REST_URL.get(),
UPSTASH_REDIS_REST_TOKEN: await env.UPSTASH_REDIS_REST_TOKEN.get(),
});
const count = await redis.incr("counter");
return new Response(JSON.stringify({ count }));

},
} satisfies ExportedHandler<Env>;
```

</CodeGroup>
After doing these modifications, you can deploy the worker to Cloudflare with `npx wrangler deploy`, and
follow the steps below to define the secrets:

- Navigate to [Upstash Console](https://console.upstash.com) and get your Redis credentials.

- In [Cloudflare Dashboard](https://dash.cloudflare.com/), Go to **Secrets Store** and add Redis credentials as secrets.

### Test and Deploy
<Frame>
<img src="/img/cloudflare-integration/redis-secrets-store.png" />
</Frame>

You can test the function locally with `npx wrangler dev`
- Under **Compute (Workers)** > **Workers & Pages**, find your worker and add these secrets as bindings.

<Frame>
<img src="/img/cloudflare-integration/redis-add-binding.png" />
</Frame>

### Deployment

<Note>
Newer deployments may revert the configurations you did in the dashboard.
While worker level secrets persist, the bindings will be gone!
</Note>

Deploy your function to Cloudflare with `npx wrangler deploy`

The endpoint of the function will be provided to you, once the deployment is done.

### Testing

Open a different terminal and test the endpoint. Note the destination
url is the same that was printed in the previous deploy step.

```bash
curl -X POST 'https://<your-worker-name>.<account-name>.workers.dev' \
-H 'Content-Type: application/json'
```

The response will be in the format of `{"count":20}`

In the logs you should see something like this:

```bash
$ npx wrangler tail

⛅️ wrangler 4.43.0
--------------------

Successfully created tail, expires at 2025-10-16T18:59:18Z
Connected to <your-worker-name>, waiting for logs...
POST https://<your-worker-name>.<account-name>.workers.dev/ - Ok @ 10/16/2025, 4:05:30 PM
```

## Repositories

Javascript:
Expand Down