Hono on Cloudflare with SST
Create and deploy a Hono API on Cloudflare with SST.
We are going to build an API with Hono, add an R2 bucket for file uploads, and deploy it using Cloudflare with SST.
Before you get started, make sure to Create your Cloudflare API token.
1. Create a project
Let’s start by creating our app.
mkdir my-hono-api && cd my-hono-apinpm init -y
Init SST
Now let’s initialize SST in our app.
npx sst@latest initnpm 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.
export CLOUDFLARE_API_TOKEN=aaaaaaaa_aaaaaaaaaaaa_aaaaaaaaexport CLOUDFLARE_DEFAULT_ACCOUNT_ID=aaaaaaaa_aaaaaaaaaaaa_aaaaaaaa
2. Add a Worker
Let’s add a Worker. Update your sst.config.ts
.
async run() { const hono = new sst.cloudflare.Worker("Hono", { url: true, handler: "index.ts", });
return { api: hono.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
.
const bucket = new sst.cloudflare.Bucket("MyBucket");
Add this above the Worker
component.
Link the bucket
Now, link the bucket to our Worker.
const hono = new sst.cloudflare.Worker("Hono", { url: true, link: [bucket], handler: "index.ts",});
4. Upload a file
We want the /
route of our API to upload a file to the R2 bucket. Create an index.ts
file and add the following.
const app = new Hono() .put("/*", async (c) => { const key = crypto.randomUUID(); await Resource.MyBucket.put(key, c.req.raw.body, { httpMetadata: { contentType: c.req.header("content-type"), }, }); return c.text(`Object created with key: ${key}`); });
export default app;
Add the imports.
import { Hono } from "hono";import { Resource } from "sst";
And install the npm packages.
npm install hono
5. Download a file
We want to download the last uploaded file if you make a GET
request to the API. Add this to your routes in index.ts
.
const app = new Hono() // ... .get("/", async (c) => { const first = await Resource.MyBucket.list().then( (res) => res.objects.sort( (a, b) => a.uploaded.getTime() - b.uploaded.getTime(), )[0], ); const result = await Resource.MyBucket.get(first.key); c.header("content-type", result.httpMetadata.contentType); return c.body(result.body); });
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.
npx sst dev
This will give you the URL of your API.
✓ Complete Hono: https://my-hono-api-jayair-honoscript.sst-15d.workers.dev
Test your app
Let’s try uploading a file from your project root. Make sure to use your API URL.
curl -X PUT --upload-file package.json https://my-hono-api-jayair-honoscript.sst-15d.workers.dev
Now head over to https://my-hono-api-jayair-honoscript.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!
npx sst deploy --stage production
You can use any stage name here but it’s good to create a new stage for production.