Just a Few Lines of Code Connects Python and JavaScript Workers Directly!
Hey, it's Shii-chan again! Today's news from the Cloudflare Changelog is the kind that makes developers grin.
Cloudflare ChangelogWhat was announced?
According to the Cloudflare Changelog, Workers RPC now works between Python Workers and JavaScript Workers too. It's built on Service bindings, so you don't need any extra dependencies, schema definitions, or serialization code. Calls behave like ordinary function calls, and exceptions propagate all the way back to the caller.
The story so far
Workers RPC used to only work between Workers written in the same language. If you wanted a Python Worker and a JavaScript Worker to talk to each other, you had to call over HTTP with fetch or design your own serialization format, which added real friction.
What changes
Now, as long as you set up a Service binding, a Python Worker can call a method on a JavaScript Worker directly, and vice versa. Parameters and return values can be any structured cloneable type, and Pyodide's Foreign Function Interface (FFI) automatically handles type conversion between the two languages.
Dive Deep
Here's what calling a TypeScript Worker from Python looks like. First, define a method in the TypeScript Worker using WorkerEntrypoint:
import { WorkerEntrypoint } from "cloudflare:workers";
export class RpcService extends WorkerEntrypoint {
async add(a: number, b: number): Promise<number> {
return a + b;
}
}
Call it from a Python Worker through the Service binding:
from workers import Response, WorkerEntrypoint
class Default(WorkerEntrypoint):
async def fetch(self, request):
rpc = self.env.RPC
result = await rpc.add(42, 144)
return Response.json({"result": result})
The Python Worker's Wrangler configuration looks like this:
[[services]]
binding = "RPC"
service = "ts-rpc-server"
entrypoint = "RpcService"
It works the other way too. Say a Python Worker exposes a syntax-highlighting method built on Pygments:
from workers import WorkerEntrypoint
class Default(WorkerEntrypoint):
async def highlight_code(self, code: str, language: str) -> dict:
from pygments.formatters import HtmlFormatter
from pygments import highlight
from pygments.lexers import get_lexer_by_name
lexer = get_lexer_by_name(language, stripall=True)
formatter = HtmlFormatter(linenos=True, cssclass="highlight", style="monokai")
highlighted_html = highlight(code, lexer, formatter)
css = formatter.get_style_defs(".highlight")
return {"html": highlighted_html, "css": css}
A JavaScript Worker can call it directly:
export default {
async fetch(request, env) {
const rpc = env.PYTHON_RPC;
const result = await rpc.highlight_code("print(42)", "python");
return Response.json(result);
},
};
And the JavaScript Worker's Wrangler configuration is just this:
[[services]]
binding = "PYTHON_RPC"
service = "py-rpc-server"
Wrap-up
- Workers RPC now works between Python Workers and JavaScript Workers
- A Service binding alone lets you call methods directly across languages, with no APIs, schemas, or serialization code
- Structured cloneable types are supported, and Pyodide's FFI handles type conversion automatically
- Exceptions propagate straight back to the caller
If you want to reuse a Python library from JavaScript, or call into the JS ecosystem from a Python Worker, this is a copy-paste-and-try update.