Skip to content

cloudflare workers #1410

Description

@konsumer

cloudflare has a js runtime that is similar to node, but different, and closely follows Web Workers API. It has a great free tier and is really cheap to run (cheaper than lambda, but similar idea of light backend single-purpose functions.) CF also has a pretty good history of respecting privacy, and resisting censorship, especially over AWS and heroku.

Is there interest in porting the backend service to CF workers? If so, I can PR for it.

Activity

  1. amark commented on Aug 15, 2025

    @amark
    Owner

    That'd be cool. Just wrapping window? What about file system etc.

  2. konsumer commented on Aug 21, 2025

    @konsumer
    Author

    Cloudflare has no window or direct filesystem, but it has persistence with KV (free-tier, very fast, edge-replicated) so it may be a bit involved to build an adapter, but I think it will work pretty nicely. It also has a free-tier edge-replicated sqlite (D1) and cloud-filesystem thing that is API-compat with AWS S3 (R2) that could all replace regular filesystem access.

    There are lots of ways to do it, but personally, I think KV is probably the most likely candidate for replacing filesystem. It's fast, writes replicate across multiple workers, and works sort of similar (the API is list - with prefix to handle directories, get, and put.)

    I also often have issues with the official herokus (usage-limits and warmup-time sometimes make it not available) so it might serve as a better default. I am also happy to implement it as a separate thing, if that makes more sense.

    Here is an example websocket worker, that uses no other libraries (hono is nice for routed APIs, for example, but this is just using the built-in stuff):

    // worker exports a HTTP handler
    // second param is env, which has any resources user setup in their wrangler.toml. In this case, I have a KV named FILES
    export default {
      async fetch(req, { FILES }) {
        // upgrade to web-socket, which should be true for any requests to this backend
        // more info could also be returned here to tell browser-users they are doing it wrong
        const upgradeHeader = req.headers.get('Upgrade')
        if (!upgradeHeader || upgradeHeader !== 'websocket') {
          return new Response('Expected Upgrade: websocket', { status: 426 });
        }
        const webSocketPair = new WebSocketPair()
        const [client, server] = Object.values(webSocketPair)
    
        // here, you implement your websocket handlers
        // async handler is optional for message
        server.accept()
        server.addEventListener('message', event => {
          // here we have access to FILES: https://developers.cloudflare.com/kv/
          console.log(event.data)
        })
    
        return new Response(null, {
          status: 101,
          webSocket: client,
        })
      }
    }

    To wrap this in a worker yourself, see Getting Started, but I am happy to provide a more complete example.

    I imagine a helper function that takes a few required params and implements all the gun stuff:

    import setupWorker from 'gun/worker'
    
    export default {
      async fetch(req, {FILES}) {
        // let user manage their own upgrade-flow, so they add their own messages and stuff
        // upgrade to web-socket, which should be true for any requests to this backend
        const upgradeHeader = req.headers.get('Upgrade')
        if (!upgradeHeader || upgradeHeader !== 'websocket') {
          return new Response('Expected Upgrade: websocket', { status: 426 });
        }
    
        // await might not be needed, if there are no async side-effects to setup
        // since the websocket message-handler itself can be async, it might slightly simplify to leave that out
        const [webSocket, server] = await setupWorker(req, FILES)
        server.accept()
    
        // here user could add more handlers to server, if they want
    
        return new Response(null, {
          status: 101,
          webSocket,
        })
      }
    }
  3. konsumer commented on Dec 1, 2025

    @konsumer
    Author

    @amark I am having trouble seeing how this fits together.

    • What is difference with ws/websocket?
    • How are these actually used? Would it be possible to provide a simple example that uses all 3?
    • Is the idea that storage is separate from message, and triggered by different options? If so, this might fit even better than I thought (I implement cf_kv, similar to localstorage, and use ws/websocket normally.)

    It might be possible to reuse websocket/ws since the interface is the same (once it's setup, like above examples.) If it works how I think, now, I just need to pass the websocket and storage interface for KV. I could even do a few, like D1 (edge-replicated sqlite, that has faster reads than KV.)

  4. k98kurz commented on Feb 8, 2026

    @k98kurz

    @konsumer any progress on this? Being able to deploy a relay to Cloudflare would be really handy, even if it was just a thin relay without any storage.

  5. amark commented on Mar 16, 2026

    @amark
    Owner

    👀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions