Backend & Cloudflare Platform Engineer

Upload Dewek: Edge-Native DAM on Cloudflare

Serverless, headless Digital Asset Management (DAM) API built natively on Cloudflare edge. Direct-to-bucket S3 presigned PUT uploads with atomic state synchronization and on-the-fly image optimization.

Year
2026
Stack
Cloudflare WorkersCloudflare R2Cloudflare D1TypeScriptHonoS3 API
GitHub ↗

Upload Dewek: A Serverless DAM on Cloudflare's Edge

What Is It?

Upload Dewek is a headless Digital Asset Management API that runs entirely on Cloudflare's edge infrastructure — no servers, no container orchestration, no cold starts.

The core flow is deceptively simple:

  1. Client requests an upload URL from the API
  2. API generates a presigned S3 PUT URL pointing directly at R2
  3. Client uploads straight to R2 — the API never touches the payload
  4. After upload, a Durable Object validates and atomically records the asset metadata in D1

This eliminates the classic anti-pattern of proxying file uploads through your application server.


Architecture

sequenceDiagram
    participant Client
    participant Worker as Cloudflare Worker<br>(Hono)
    participant R2 as R2 Bucket
    participant D1 as D1 Database
    participant DO as Durable Object
 
    Client->>Worker: POST /upload/init
    Worker->>R2: Generate presigned PUT URL
    Worker->>D1: Record pending upload
    Worker-->>Client: Return presigned URL
    
    Client->>R2: PUT {presigned-url} (Direct)
    
    Client->>Worker: POST /upload/confirm
    Worker->>DO: Atomic state flip<br>(pending → confirmed)
    DO->>D1: Update status

Why Durable Objects for Confirmation?

The confirm step uses a Durable Object (not a plain Worker) because multiple concurrent confirmation requests for the same asset need serialization. A regular Worker is stateless — race conditions could result in duplicate asset records in D1. The DO acts as a per-asset mutex.


Key Implementation Details

Presigned URL Generation

R2's S3-compatible API supports presigned URLs natively. The signature is computed using @aws-sdk/signature-v4 running inside the Worker:

import { S3RequestPresigner } from "@aws-sdk/s3-request-presigner";
import { createRequest } from "@aws-sdk/util-create-request";
 
const presigner = new S3RequestPresigner({
  credentials: {
    accessKeyId: env.R2_ACCESS_KEY_ID,
    secretAccessKey: env.R2_SECRET_ACCESS_KEY,
  },
  region: "auto",
  sha256: Hash.bind(null, "sha256"),
});

The URL expires in 15 minutes, scoped to a specific key and content-type.

On-the-Fly Image Optimization

Cloudflare Images transforms are applied at the CDN layer — no compute needed:

https://assets.dewek.id/{asset-id}?width=800&format=webp&quality=85

This is handled by a Worker Route that intercepts image requests and applies transforms before serving from R2 cache.


Design Decisions

DecisionRationale
Presigned PUTs over proxyEliminates Worker egress costs and bandwidth limits
D1 over KVRelational queries for asset search/filtering
Durable Objects for confirmSerialized state transitions, no race conditions
Hono over itty-routerType-safe routing, middleware composability

Current Status

Active development. Core upload/confirm/serve flow is complete. Working on: