new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Cloudflare Workers · all subjects

framework-guides

313 notes in this subject, read out of this brain and free to use. This is page 4 of 6.

Deploy Python Worker with pywrangler

To deploy a Python Worker to Cloudflare, run: uv run pywrangler deploy

Getting started with FastAPI in Python Workers

Clone the cloudflare/python-workers-examples repository and run the FastAPI example with: git clone https://github.com/cloudflare/python-workers-examples, then cd python-workers-examples/03-fastapi, then uv run pywrangler dev.

ASGI server in Python Workers runtime

The Python Workers runtime includes a built-in ASGI server implementation available at workers-py packages/runtime-sdk/src/asgi.py. This server handles raw socket operations on behalf of FastAPI applications, allowing FastAPI to work directly in Python Workers.

FastAPI support in Python Workers

FastAPI is supported in Python Workers. FastAPI applications use the Asynchronous Server Gateway Interface (ASGI) protocol, which means FastAPI never reads from or writes to a socket itself. An ASGI application expects to be hooked up to an ASGI server, typically uvicorn. The Python Workers runtime provides a built-in ASGI server that you can use directly in your Python Worker to run FastAPI applications.

FastAPI Worker entry point structure

A FastAPI application in Python Workers requires a WorkerEntrypoint class with an async fetch method that delegates to the ASGI server using asgi.fetch(app, request, self.env), passing the FastAPI app instance, the request object, and the environment bindings.

Accessing environment variables in FastAPI Workers

Environment variables in FastAPI Workers can be accessed through the request scope: req.scope['env'] provides access to environment bindings passed to the ASGI server.

FastAPI example with basic routing and models

Example FastAPI Worker showing GET and POST endpoints with Pydantic models. Demonstrates: GET / returning JSON, POST /items/ accepting a Pydantic BaseModel (Item with name, description, price, tax fields), PUT /items/{item_id} with optional query parameters, and GET /items/{item_id} with path parameters. All endpoints are async functions.

PyEmscripten wheels availability limitation

WebAssembly support for Python packages is in early stages. Some packages may not yet be available as PyEmscripten wheels on PyPI. If a needed package lacks PyEmscripten wheels, contact the package maintainers to request them, or start a thread in the Python Packages Discussions on the Cloudflare Workers Runtime GitHub repository for assistance.

Supported Python package types

Python Workers support pure Python packages and PyEmscripten Python packages from PyPI. Additionally, Python Workers support packages included in Pyodide.

Async-only HTTP client libraries

Only HTTP libraries that make requests asynchronously are supported in Python Workers. Currently supported async HTTP libraries are aiohttp and httpx. Alternatively, use the fetch() API from JavaScript via Python Workers' foreign function interface to make HTTP requests.

LangChain example on Workers Python runtime

This example demonstrates using LangChain with the Workers Python runtime. It imports WorkerEntrypoint and Response from the workers module, creates a PromptTemplate to complete sentences, initializes an OpenAI LLM with an API key from the environment (self.env.API_KEY), chains the prompt and LLM together, and uses ainvoke to asynchronously invoke the chain with a profession parameter.

LangChain Python packages available on Workers

The Workers runtime provides three LangChain Python packages: langchain version 0.1.8, langchain-core version 0.1.25, and langchain-openai version 0.0.6.

Running LangChain example locally with pywrangler

To run the LangChain example locally, clone the cloudflare/python-workers-examples repository, navigate to the 05-langchain directory, and run 'uv run pywrangler dev'.

Rust crates supported in Cloudflare Workers

Popular Rust crates that have been confirmed to work with Cloudflare Workers when using workers-rs or wasm-bindgen include: time, tracing, reqwest, tokio-postgres, and hyper. Many Rust crates can be compiled to the wasm32-unknown-unknown target supported by Workers, though this may require disabling default features or enabling Wasm-specific features.

time crate Wasm support requires wasm-bindgen feature

The time crate must have the wasm-bindgen feature enabled to obtain timing information from JavaScript when used in Wasm. Many crates made Wasm-friendly use the time crate instead of std::time.

tracing crate setup for Workers

Tracing can be enabled using the tracing-web crate and the time feature for tracing-subscriber. Due to timing limitations on Workers, spans will have identical start and end times unless they encompass I/O.

reqwest library works with Workers fetch API

The reqwest library can be compiled to Wasm and automatically hooks into the JavaScript fetch API using wasm-bindgen.

tokio-postgres configuration for Workers

tokio-postgres can be compiled to Wasm and must be configured to use a Socket from workers-rs to function in Workers.

hyper crate partial support in Workers

The hyper crate contains two HTTP clients: the lower-level conn module and the higher-level Client. The conn module can be used with Workers Socket, however Client requires timing dependencies which are not yet Wasm friendly.

Wasm target for Rust Workers

Cloudflare Workers supports the wasm32-unknown-unknown Rust target for compiling to WebAssembly.

Event macro in workers-rs

The event macro in workers-rs allows defining entrypoints to a Worker. It supports the following events: fetch (invoked by incoming HTTP requests), scheduled (invoked by Cron Triggers), queue (invoked by incoming message batches from Queues, requires queue feature in Cargo.toml), and start (invoked when the Worker is first launched).

Deploy Rust Workers

To deploy a Rust Workers project, run 'npx wrangler deploy'. This deploys the Worker to a *.workers.dev subdomain or a Custom Domain if configured. If neither is configured, Wrangler will prompt during deployment to set one up.

wasm-bindgen for Wasm Workers

wasm-bindgen provides the glue code needed to import runtime APIs to and export event handlers from the Wasm module. It also provides js-sys, which implements types for interacting with JavaScript objects. workers-rs handles conversion to and from JavaScript objects and interaction with JavaScript runtime APIs.

Async support in Rust Workers

wasm-bindgen-futures provides interoperability between Rust Futures and JavaScript Promises. workers-rs invokes the entire event handler function using spawn_local, allowing async Rust programming which is converted into a single JavaScript Promise run on the JavaScript event loop.

worker-build bundling tool

worker-build is a build tool included in workers-rs that: (1) creates a JavaScript entrypoint script that properly invokes the module using wasm-bindgen's JavaScript API, (2) invokes web-pack to minify and bundle JavaScript code, and (3) outputs a directory structure that Wrangler can use to bundle and deploy the final Worker. It is invoked by default in the template project via a custom build command in wrangler.toml.

Rust Wasm binary size optimization

The template project pre-configures size optimizations in Cargo.toml: lto = true, strip = true, and codegen-units = 1. worker-bundle automatically invokes wasm-opt to further optimize binary size before upload.

Manual wasm-bindgen patching for Workers

When using wasm-bindgen without workers-rs or worker-build, patch the JavaScript output: (1) Run 'wasm-pack build --target bundler' as normal, (2) patch the JavaScript file to detect runtime environment and switch between node and workerd syntax for WebAssembly instantiation using process.release.name check, and (3) import the function directly from the patched JavaScript file in your Worker entrypoint.

Router API in workers-rs

workers-rs provides a Router struct that implements a convenient routing API to serve multiple paths from one Worker.

workers-rs crate for Rust Workers

Cloudflare Workers provides support for Rust via the workers-rs crate, which makes Runtime APIs and bindings to developer platform products such as Workers KV, R2, and Queues available directly from Rust code.

Rust prerequisites for Workers

To build Rust Workers, you need: a recent version of Rust, npm, the Rust wasm32-unknown-unknown toolchain (installed via 'rustup target add wasm32-unknown-unknown'), and the cargo-generate sub-command (installed via 'cargo install cargo-generate').

Create Rust Workers project template

To generate a Rust Workers project template, run the command: cargo generate cloudflare/workers-rs

Project structure for Rust Workers

A Rust Workers project template includes: Cargo.toml (standard Rust project configuration with best-practice settings for building Wasm on Workers), wrangler.toml (Wrangler configuration pre-populated with a custom build command to invoke worker-build), and src directory (Rust source directory with Hello World Worker).

Rust Workers fetch handler signature

The Rust fetch handler is defined with the #[event(fetch)] macro and has the signature: async fn main(req: Request, env: Env, ctx: Context) -> Result<Response>. This matches the JavaScript Workers API signature.

Frontend framework integration

Wrangler handles frontend and server-side rendering frameworks by using their build output. The Cloudflare Vite plugin integrates directly with Vite-powered frameworks.

Workers supports popular frameworks

Cloudflare Workers supports a number of popular frameworks with framework-specific guides available for getting started.

When to use Workers frameworks vs building from scratch

Use a framework for most front-end applications as they come with ready-to-use components, pre-defined architecture, and community support. Build from scratch if you want to learn core functionalities, work on a simple project that doesn't need a framework, optimize for performance by minimizing dependencies, need complete control, or want to build your own framework.

Netlify features not supported by Workers

Netlify-specific features are not supported by Cloudflare Workers. Review the Workers compatibility matrix for more information on what features are supported when migrating from Netlify.

Finding Netlify build command and output directory

In the Netlify Dashboard, navigate to Project configuration, then Build & deploy, and locate the Build settings card. This card contains the Build command field (such as npm run build) and the Publish directory field (such as .next). These values are needed when creating the wrangler configuration file for Workers.

Framework-specific migration guides available

Some frameworks including Next.js and Astro with on-demand rendering have specific guides for migrating to Cloudflare Workers. Check the framework guides for a 'Deploy an existing project on Workers' guide before following the generic migration steps.

Migrate to Workers compatibility matrix

Review the Workers compatibility matrix in the migration guides section to understand what Vercel features and capabilities are supported when migrating to Cloudflare Workers.

Vercel to Workers migration tutorial overview

To migrate a Vercel application to Cloudflare Workers, you need an existing project already deployed on Vercel. Vercel-specific features are not supported by Cloudflare Workers. Framework-specific guides are available for some frameworks like Next.js and Astro with on-demand rendering.

Find Vercel build command and output directory

In your Vercel Dashboard, go to the Settings tab for your project and find the Build & Development settings panel. There you will find the Build Command and Output Directory fields. If using a framework, these values may show defaults even if not explicitly filled in. Save these values as they are needed for deploying to Cloudflare Workers.

File-based routing migration from Pages Functions

Workers supports file-based routing through popular frameworks. To migrate from Pages Functions folder-based routing, either use a framework that implements file-based routing (such as HonoX) or use Wrangler to compile the functions folder into a Worker.

Full-stack frameworks supported by Workers

Full-stack frameworks are natively supported by Workers. The supported frameworks are listed in the framework guides documentation, including both general full-stack web apps and additional web frameworks.

Static Site Generation (SSG) definition and frameworks

Static Site Generation (SSG) applications are web applications which are predominantly built or prerendered ahead-of-time. They are often built with frameworks such as Gatsby or Docusaurus. The build process produces many HTML files and accompanying client-side resources including JavaScript bundles, CSS stylesheets, images, and fonts. Data is either static, fetched and compiled into the HTML at build-time, or fetched by the client from an API with client-side requests.

Complete todo list application example

const html = (todos) => ` <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>Todos</title> <link href="https://cdn.jsdelivr.net/npm/tailwindcss/dist/tailwind.min.css" rel="stylesheet"></link> </head> <body class="bg-blue-100"> <div class="w-full h-full flex content-center justify-center mt-8"> <div class="bg-white shadow-md rounded px-8 pt-6 py-8 mb-4"> <h1 class="block text-grey-800 text-md font-bold mb-2">Todos</h1> <div class="flex"> <input class="shadow appearance-none border rounded w-full py-2 px-3 text-grey-800 leading-tight focus:outline-none focus:shadow-outline" type="text" name="name" placeholder="A new todo"></input> <button class="bg-blue-500 hover:bg-blue-800 text-white font-bold ml-2 py-2 px-4 rounded focus:outline-none focus:shadow-outline" id="create" type="submit">Create</button> </div> <div class="mt-4" id="todos"></div> </div> </div> </body> <script> window.todos = ${todos} var updateTodos = function() { fetch("/", { method: "PUT", body: JSON.stringify({ todos: window.todos }) }) populateTodos() } var completeTodo = function(evt) { var checkbox = evt.target var todoElement = checkbox.parentNode var newTodoSet = [].concat(window.todos) var todo = newTodoSet.find(t => t.id == todoElement.dataset.todo) todo.completed = !todo.completed window.todos = newTodoSet updateTodos() } var populateTodos = function() { var todoContainer = document.querySelector("#todos") todoContainer.innerHTML = null window.todos.forEach(todo => { var el = document.createElement("div") el.className = "border-t py-4" el.dataset.todo = todo.id var name = document.createElement("span") name.className = todo.completed ? "line-through" : "" name.textContent = todo.name var checkbox = document.createElement("input") checkbox.className = "mx-4" checkbox.type = "checkbox" checkbox.checked = todo.completed ? 1 : 0 checkbox.addEventListener("click", completeTodo) el.appendChild(checkbox) el.appendChild(name) todoContainer.appendChild(el) }) } populateTodos() var createTodo = function() { var input = document.querySelector("input[name=name]") if (input.value.length) { window.todos = [].concat(todos, { id: window.todos.length + 1, name: input.value, completed: false }) input.value = "" updateTodos() } } document.querySelector("#create").addEventListener("click", createTodo) </script> </html> `; export default { async fetch(request, env, ctx) { const defaultData = { todos: [ { id: 1, name: "Finish the Cloudflare Workers blog post", completed: false, }, ], }; const setCache = (key, data) => env.TODOS.put(key, data); const getCache = (key) => env.TODOS.get(key); const ip = request.headers.get("CF-Connecting-IP"); const myKey = `data-${ip}`; if (request.method === "PUT") { const body = await request.text(); try { JSON.parse(body); await setCache(myKey, body); return new Response(body, { status: 200 }); } catch (err) { return new Response(err, { status: 500 }); } } let data; const cache = await getCache(myKey); if (!cache) { await setCache(myKey, JSON.stringify(defaultData)); data = defaultData; } else { data = JSON.parse(cache); } const body = html(JSON.stringify(data.todos).replace(/</g, "\\u003c")); return new Response(body, { headers: { "Content-Type": "text/html", }, }); }, }; This example demonstrates a complete Jamstack todo list application using Workers, KV for persistence, and dynamic HTML rendering with client-side interactivity for creating and marking todos complete.

Parse GitHub issue reference string

Create a utility function to parse GitHub issue references in the format owner/repo#issue_number. Use regex: /(?<owner>[\w.-]*)\/(?<repo>[\w.-]*)\#(?<issue_number>\d*)/ with named capture groups. The parseGhIssueString function returns an object with owner, repo, and issue_number properties extracted from the input text.

Slack slash command response with response_type

Return responses to slash commands as JSON with blocks and response_type. Set response_type to 'in_channel' to display the response to all users in the channel, or omit it to default to 'ephemeral' (visible only to the user who issued the command). Example: c.json({ blocks, response_type: 'in_channel' }).

Build a Slackbot tutorial overview

This tutorial teaches how to build a Slackbot with Cloudflare Workers using Hono and TypeScript. The bot integrates with GitHub webhooks to send Slack messages when issues are created or updated, and provides a slash command to look up GitHub issues from within Slack. The tutorial is recommended for people familiar with web application development and assumes knowledge of tools like Node and Express.

Slack Incoming Webhook configuration for Workers

To post messages from a Cloudflare Worker to a Slack channel, create an Incoming Webhook in Slack's UI at api.slack.com/apps. Navigate to Incoming Webhooks, select Add New Webhook to Workspace, choose the target channel or direct message, and authorize the webhook. The resulting webhook URL is used to send messages to Slack and should be stored securely as a secret via wrangler secret put.

Slack Slash Command configuration for Workers

Create a Slash Command in Slack's dashboard (via Slash Commands section). For example, configure /issue as the command with the Request URL set to a path on the Worker application, such as https://myworkerurl.com/lookup. When users type the slash command, Slack sends an HTTP POST request with application/x-www-form-urlencoded content type containing the command text and metadata.

Initialize Slackbot project with C3

Use the C3 (create-cloudflare-cli) command to initialize a new project: npm create cloudflare@latest slack-bot. Select Framework Starter, then Hono as the development framework. Answer No to deployment. This creates a Hono project ready for development.

Hono project structure with app.route()

In Hono, child applications can be added to a parent application using app.route(path, childApp). This allows organizing endpoints across multiple files. For example, app.route('/api/v1', api) adds routes from the api child application under the /api/v1 path. The Slackbot uses app.route('/lookup', lookup) and app.route('/webhook', webhook) to organize lookup and webhook handling.

TypeScript types for Slackbot bindings

Define a Bindings type in src/types.ts containing environment variables: type Bindings = { SLACK_WEBHOOK_URL: string }. Also define an Issue type with properties: html_url, title, body, state, created_at, number, and user. Define a User type with html_url, login, and avatar_url. These types provide TypeScript type safety for environment variables and API responses.

Parse Slack slash command payload

Slack sends slash command requests as HTTP POST with application/x-www-form-urlencoded content. Parse the payload using c.req.parseBody() to access the text field containing the command argument. Example: const { text } = await c.req.parseBody(). If text is not a string, return c.notFound().

Fetch GitHub issue data

Create a utility function to fetch issue data from GitHub API: const url = `https://api.github.com/repos/${owner}/${repo}/issues/${issue_number}`; const headers = { "User-Agent": "simple-worker-slack-bot" }; return fetch(url, { headers }). Parse the response with response.json<Issue>() to get typed issue data.

Construct Slack messages with Block Kit

Use Slack's Block Kit to format messages with section blocks containing mrkdwn text and image accessories. Format links as <URL|Display Text>, bold text as *text*, and construct text_lines array joining with newlines. Return an array with a single section block object containing type: 'section', text object with type: 'mrkdwn' and text property, and accessory with type: 'image', image_url, and alt_text.

Handle errors in Hono routes

Define custom error handling in Hono using app.onError((_e, c) => { ... }). For the lookup route, return a user-friendly text message via c.text(message). For the webhook route, return a JSON error response with status 500: c.json({ message: 'Unable to handle webhook' }, 500).

Parse GitHub IssueEvent webhook payload

GitHub IssueEvent webhooks send JSON payloads containing action, issue, and repository properties. Parse with c.req.json() to access these fields. The action property describes what happened (opened, closed, locked, etc.). Construct issue_string from repository.owner.login, repository.name, and issue.number.

Send messages to Slack via webhook URL

Post formatted messages to Slack by making an HTTP POST request to the stored SLACK_WEBHOOK_URL with JSON body containing blocks. Example: fetch(c.env.SLACK_WEBHOOK_URL, { body: JSON.stringify({ blocks }), method: 'POST', headers: { 'Content-Type': 'application/json' } }). Access the webhook URL via c.env.SLACK_WEBHOOK_URL when Bindings type includes SLACK_WEBHOOK_URL.

Give your agent this brain