Skip to content

Cloudflare Workers with SST

Create and deploy a Cloudflare Worker as an API with SST.

We are going to build an API with a Cloudflare Worker, add an R2 bucket for file uploads, and deploy it using SST.

Before you get started, make sure to Create your Cloudflare API token.


1. Create a project

Let’s start by creating our app.

Terminal window
mkdir my-worker && cd my-worker
npm init -y

Init SST

Now let’s initialize SST in our app.

Terminal window
npx sst@latest init
npm install

Select the defaults and pick Cloudflare. This’ll create a sst.config.ts file in your project root.


Set the Cloudflare API token

You can save your Cloudflare API token in a .env file or just set it directly.

Terminal window
export CLOUDFLARE_API_TOKEN=aaaaaaaa_aaaaaaaaaaaa_aaaaaaaa
export CLOUDFLARE_DEFAULT_ACCOUNT_ID=aaaaaaaa_aaaaaaaaaaaa_aaaaaaaa

2. Add a Worker

Let’s add a Worker. Update your sst.config.ts.

sst.config.ts
async run() {
const worker = new sst.cloudflare.Worker("MyWorker", {
handler: "./index.ts",
url: true,
});
return {
api: worker.url,
};
}

We are enabling the Worker URL, so we can use it as our API.


3. Add an R2 Bucket

Let’s add an R2 bucket for file uploads. Update your sst.config.ts.

sst.config.ts
const bucket = new sst.cloudflare.Bucket("MyBucket");

Add this above the Worker component.

Now, link the bucket to our Worker.

sst.config.ts
const worker = new sst.cloudflare.Worker("MyWorker", {
handler: "./index.ts",
link: [bucket],
url: true,
});

4. Upload a file

We want our API to upload a file to the R2 bucket if you make a PUT request to it. Create an index.ts file and add the following.

index.ts
export default {
async fetch(req: Request) {
if (req.method == "PUT") {
const key = crypto.randomUUID();
await Resource.MyBucket.put(key, req.body, {
httpMetadata: {
contentType: req.headers.get("content-type"),
},
});
return new Response(`Object created with key: ${key}`);
}
},
};

Import the SDK.

index.ts
import { Resource } from "sst";

5. Download a file

We want to download the last uploaded file if you make a GET request to the API. Add this to the fetch function in your index.ts file.

index.ts
if (req.method == "GET") {
const first = await Resource.MyBucket.list().then(
(res) =>
res.objects.toSorted(
(a, b) => a.uploaded.getTime() - b.uploaded.getTime(),
)[0],
);
const result = await Resource.MyBucket.get(first.key);
return new Response(result.body, {
headers: {
"content-type": result.httpMetadata.contentType,
},
});
}

We are getting a list of the files in the files in the bucket with Resource.MyBucket.list() and we are getting a file for the given key with Resource.MyBucket.get().


Start dev mode

Start your app in dev mode.

Terminal window
npx sst dev

This will give you the URL of your API.

+ Complete
api: https://start-cloudflare-jayair-myworkerscript.sst-15d.workers.dev

Test your app

Let’s try uploading a file from your project root. Make sure to use your API URL.

Terminal window
curl --upload-file package.json https://start-cloudflare-jayair-myworkerscript.sst-15d.workers.dev

Now head over to https://start-cloudflare-jayair-myworkerscript.sst-15d.workers.dev in your browser and it’ll load the file you just uploaded.


6. Deploy your app

Finally, let’s deploy your app!

Terminal window
npx sst deploy --stage production

You can use any stage name here but it’s good to create a new stage for production.