Cross-language RPC between Python and JavaScript Workers
You can now call methods between Python and JavaScript Workers using Workers RPC. This works through Service bindings without extra dependencies, schema definitions, or serialization code.
Cross-language RPC calls behave like ordinary function calls. Exceptions propagate to the call site. You can pass structured cloneable types ↗ as parameters or return values, and Pyodide Foreign Function Interface (FFI) automatically converts types between languages.
Call a TypeScript Worker from Python
Define a method in a TypeScript Worker:
index.jsjs
<span class="line"><span class="nb-shiki-1itgoe">import</span><span class="nb-shiki-140thh"> { WorkerEntrypoint } </span><span class="nb-shiki-1itgoe">from</span><span class="nb-shiki-mdbnqw"> "cloudflare:workers"</span><span class="nb-shiki-140thh">;</span></span>
<span class="line"></span>
<span class="line"><span class="nb-shiki-1itgoe">export</span><span class="nb-shiki-1itgoe"> class</span><span class="nb-shiki-1t8gfj"> RpcService</span><span class="nb-shiki-1itgoe"> extends</span><span class="nb-shiki-1t8gfj"> WorkerEntrypoint</span><span class="nb-shiki-140thh"> {</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> async</span><span class="nb-shiki-1t8gfj"> add</span><span class="nb-shiki-140thh">(</span><span class="nb-shiki-1jdh33">a</span><span class="nb-shiki-140thh">, </span><span class="nb-shiki-1jdh33">b</span><span class="nb-shiki-140thh">) {</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> return</span><span class="nb-shiki-140thh"> a </span><span class="nb-shiki-1itgoe">+</span><span class="nb-shiki-140thh"> b;</span></span>
<span class="line"><span class="nb-shiki-140thh"> }</span></span>
<span class="line"><span class="nb-shiki-140thh">}</span></span>
index.tsts
<span class="line"><span class="nb-shiki-1itgoe">import</span><span class="nb-shiki-140thh"> { WorkerEntrypoint } </span><span class="nb-shiki-1itgoe">from</span><span class="nb-shiki-mdbnqw"> "cloudflare:workers"</span><span class="nb-shiki-140thh">;</span></span>
<span class="line"></span>
<span class="line"><span class="nb-shiki-1itgoe">export</span><span class="nb-shiki-1itgoe"> class</span><span class="nb-shiki-1t8gfj"> RpcService</span><span class="nb-shiki-1itgoe"> extends</span><span class="nb-shiki-1t8gfj"> WorkerEntrypoint</span><span class="nb-shiki-140thh"> {</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> async</span><span class="nb-shiki-1t8gfj"> add</span><span class="nb-shiki-140thh">(</span><span class="nb-shiki-1jdh33">a</span><span class="nb-shiki-1itgoe">:</span><span class="nb-shiki-dzsirb"> number</span><span class="nb-shiki-140thh">, </span><span class="nb-shiki-1jdh33">b</span><span class="nb-shiki-1itgoe">:</span><span class="nb-shiki-dzsirb"> number</span><span class="nb-shiki-140thh">)</span><span class="nb-shiki-1itgoe">:</span><span class="nb-shiki-1t8gfj"> Promise</span><span class="nb-shiki-140thh"><</span><span class="nb-shiki-dzsirb">number</span><span class="nb-shiki-140thh">> {</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> return</span><span class="nb-shiki-140thh"> a </span><span class="nb-shiki-1itgoe">+</span><span class="nb-shiki-140thh"> b;</span></span>
<span class="line"><span class="nb-shiki-140thh"> }</span></span>
<span class="line"><span class="nb-shiki-140thh">}</span></span>
Call it from a Python Worker through a Service binding:
<span class="line"><span class="nb-shiki-1itgoe">from</span><span class="nb-shiki-140thh"> workers </span><span class="nb-shiki-1itgoe">import</span><span class="nb-shiki-140thh"> Response, WorkerEntrypoint</span></span>
<span class="line"></span>
<span class="line"><span class="nb-shiki-1itgoe">class</span><span class="nb-shiki-1t8gfj"> Default</span><span class="nb-shiki-140thh">(</span><span class="nb-shiki-1t8gfj">WorkerEntrypoint</span><span class="nb-shiki-140thh">):</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> async</span><span class="nb-shiki-1itgoe"> def</span><span class="nb-shiki-1t8gfj"> fetch</span><span class="nb-shiki-140thh">(self, request):</span></span>
<span class="line"><span class="nb-shiki-140thh"> rpc </span><span class="nb-shiki-1itgoe">=</span><span class="nb-shiki-dzsirb"> self</span><span class="nb-shiki-140thh">.env.</span><span class="nb-shiki-dzsirb">RPC</span></span>
<span class="line"><span class="nb-shiki-140thh"> result </span><span class="nb-shiki-1itgoe">=</span><span class="nb-shiki-1itgoe"> await</span><span class="nb-shiki-140thh"> rpc.add(</span><span class="nb-shiki-dzsirb">42</span><span class="nb-shiki-140thh">, </span><span class="nb-shiki-dzsirb">144</span><span class="nb-shiki-140thh">)</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> return</span><span class="nb-shiki-140thh"> Response.json({</span><span class="nb-shiki-mdbnqw">"result"</span><span class="nb-shiki-140thh">: result})</span></span>
Configure the Service binding in the Python Worker's Wrangler configuration:
<span class="line"><span class="nb-shiki-140thh">{</span></span>
<span class="line"><span class="nb-shiki-dzsirb"> "services"</span><span class="nb-shiki-140thh">: [</span></span>
<span class="line"><span class="nb-shiki-140thh"> {</span></span>
<span class="line"><span class="nb-shiki-dzsirb"> "binding"</span><span class="nb-shiki-140thh">: </span><span class="nb-shiki-mdbnqw">"RPC"</span><span class="nb-shiki-140thh">,</span></span>
<span class="line"><span class="nb-shiki-dzsirb"> "service"</span><span class="nb-shiki-140thh">: </span><span class="nb-shiki-mdbnqw">"ts-rpc-server"</span><span class="nb-shiki-140thh">,</span></span>
<span class="line"><span class="nb-shiki-dzsirb"> "entrypoint"</span><span class="nb-shiki-140thh">: </span><span class="nb-shiki-mdbnqw">"RpcService"</span></span>
<span class="line"><span class="nb-shiki-140thh"> }</span></span>
<span class="line"><span class="nb-shiki-140thh"> ]</span></span>
<span class="line"><span class="nb-shiki-140thh">}</span></span>
<span class="line"><span class="nb-shiki-140thh">[[</span><span class="nb-shiki-1t8gfj">services</span><span class="nb-shiki-140thh">]]</span></span>
<span class="line"><span class="nb-shiki-140thh">binding = </span><span class="nb-shiki-mdbnqw">"RPC"</span></span>
<span class="line"><span class="nb-shiki-140thh">service = </span><span class="nb-shiki-mdbnqw">"ts-rpc-server"</span></span>
<span class="line"><span class="nb-shiki-140thh">entrypoint = </span><span class="nb-shiki-mdbnqw">"RpcService"</span></span>
Call a Python Worker from JavaScript
Define a method in a Python Worker:
<span class="line"><span class="nb-shiki-1itgoe">from</span><span class="nb-shiki-140thh"> workers </span><span class="nb-shiki-1itgoe">import</span><span class="nb-shiki-140thh"> WorkerEntrypoint</span></span>
<span class="line"></span>
<span class="line"><span class="nb-shiki-1itgoe">class</span><span class="nb-shiki-1t8gfj"> Default</span><span class="nb-shiki-140thh">(</span><span class="nb-shiki-1t8gfj">WorkerEntrypoint</span><span class="nb-shiki-140thh">):</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> async</span><span class="nb-shiki-1itgoe"> def</span><span class="nb-shiki-1t8gfj"> highlight_code</span><span class="nb-shiki-140thh">(self, code: </span><span class="nb-shiki-dzsirb">str</span><span class="nb-shiki-140thh">, language: </span><span class="nb-shiki-dzsirb">str</span><span class="nb-shiki-140thh">) -> </span><span class="nb-shiki-dzsirb">dict</span><span class="nb-shiki-140thh">:</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> from</span><span class="nb-shiki-140thh"> pygments.formatters </span><span class="nb-shiki-1itgoe">import</span><span class="nb-shiki-140thh"> HtmlFormatter</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> from</span><span class="nb-shiki-140thh"> pygments </span><span class="nb-shiki-1itgoe">import</span><span class="nb-shiki-140thh"> highlight</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> from</span><span class="nb-shiki-140thh"> pygments.lexers </span><span class="nb-shiki-1itgoe">import</span><span class="nb-shiki-140thh"> get_lexer_by_name</span></span>
<span class="line"></span>
<span class="line"><span class="nb-shiki-140thh"> lexer </span><span class="nb-shiki-1itgoe">=</span><span class="nb-shiki-140thh"> get_lexer_by_name(language, </span><span class="nb-shiki-1jdh33">stripall</span><span class="nb-shiki-1itgoe">=</span><span class="nb-shiki-dzsirb">True</span><span class="nb-shiki-140thh">)</span></span>
<span class="line"><span class="nb-shiki-140thh"> formatter </span><span class="nb-shiki-1itgoe">=</span><span class="nb-shiki-140thh"> HtmlFormatter(</span><span class="nb-shiki-1jdh33">linenos</span><span class="nb-shiki-1itgoe">=</span><span class="nb-shiki-dzsirb">True</span><span class="nb-shiki-140thh">, </span><span class="nb-shiki-1jdh33">cssclass</span><span class="nb-shiki-1itgoe">=</span><span class="nb-shiki-mdbnqw">"highlight"</span><span class="nb-shiki-140thh">, </span><span class="nb-shiki-1jdh33">style</span><span class="nb-shiki-1itgoe">=</span><span class="nb-shiki-mdbnqw">"monokai"</span><span class="nb-shiki-140thh">)</span></span>
<span class="line"><span class="nb-shiki-140thh"> highlighted_html </span><span class="nb-shiki-1itgoe">=</span><span class="nb-shiki-140thh"> highlight(code, lexer, formatter)</span></span>
<span class="line"><span class="nb-shiki-140thh"> css </span><span class="nb-shiki-1itgoe">=</span><span class="nb-shiki-140thh"> formatter.get_style_defs(</span><span class="nb-shiki-mdbnqw">".highlight"</span><span class="nb-shiki-140thh">)</span></span>
<span class="line"></span>
<span class="line"><span class="nb-shiki-1itgoe"> return</span><span class="nb-shiki-140thh"> {</span></span>
<span class="line"><span class="nb-shiki-mdbnqw"> "html"</span><span class="nb-shiki-140thh">: highlighted_html,</span></span>
<span class="line"><span class="nb-shiki-mdbnqw"> "css"</span><span class="nb-shiki-140thh">: css</span></span>
<span class="line"><span class="nb-shiki-140thh"> }</span></span>
Call it from a JavaScript Worker through a Service binding:
index.jsjs
<span class="line"><span class="nb-shiki-1itgoe">export</span><span class="nb-shiki-1itgoe"> default</span><span class="nb-shiki-140thh"> {</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> async</span><span class="nb-shiki-1t8gfj"> fetch</span><span class="nb-shiki-140thh">(</span><span class="nb-shiki-1jdh33">request</span><span class="nb-shiki-140thh">, </span><span class="nb-shiki-1jdh33">env</span><span class="nb-shiki-140thh">) {</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> const</span><span class="nb-shiki-dzsirb"> rpc</span><span class="nb-shiki-1itgoe"> =</span><span class="nb-shiki-140thh"> env.</span><span class="nb-shiki-dzsirb">PYTHON_RPC</span><span class="nb-shiki-140thh">;</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> const</span><span class="nb-shiki-dzsirb"> result</span><span class="nb-shiki-1itgoe"> =</span><span class="nb-shiki-1itgoe"> await</span><span class="nb-shiki-140thh"> rpc.</span><span class="nb-shiki-1t8gfj">highlight_code</span><span class="nb-shiki-140thh">(</span><span class="nb-shiki-mdbnqw">"print(42)"</span><span class="nb-shiki-140thh">, </span><span class="nb-shiki-mdbnqw">"python"</span><span class="nb-shiki-140thh">);</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> return</span><span class="nb-shiki-140thh"> Response.</span><span class="nb-shiki-1t8gfj">json</span><span class="nb-shiki-140thh">(result);</span></span>
<span class="line"><span class="nb-shiki-140thh"> },</span></span>
<span class="line"><span class="nb-shiki-140thh">};</span></span>
index.tsts
<span class="line"><span class="nb-shiki-1itgoe">export</span><span class="nb-shiki-1itgoe"> default</span><span class="nb-shiki-140thh"> {</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> async</span><span class="nb-shiki-1t8gfj"> fetch</span><span class="nb-shiki-140thh">(</span><span class="nb-shiki-1jdh33">request</span><span class="nb-shiki-140thh">, </span><span class="nb-shiki-1jdh33">env</span><span class="nb-shiki-140thh">) {</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> const</span><span class="nb-shiki-dzsirb"> rpc</span><span class="nb-shiki-1itgoe"> =</span><span class="nb-shiki-140thh"> env.</span><span class="nb-shiki-dzsirb">PYTHON_RPC</span><span class="nb-shiki-140thh">;</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> const</span><span class="nb-shiki-dzsirb"> result</span><span class="nb-shiki-1itgoe"> =</span><span class="nb-shiki-1itgoe"> await</span><span class="nb-shiki-140thh"> rpc.</span><span class="nb-shiki-1t8gfj">highlight_code</span><span class="nb-shiki-140thh">(</span><span class="nb-shiki-mdbnqw">"print(42)"</span><span class="nb-shiki-140thh">, </span><span class="nb-shiki-mdbnqw">"python"</span><span class="nb-shiki-140thh">);</span></span>
<span class="line"><span class="nb-shiki-1itgoe"> return</span><span class="nb-shiki-140thh"> Response.</span><span class="nb-shiki-1t8gfj">json</span><span class="nb-shiki-140thh">(result);</span></span>
<span class="line"><span class="nb-shiki-140thh"> },</span></span>
<span class="line"><span class="nb-shiki-140thh">};</span></span>
Configure the Service binding in the JavaScript Worker's Wrangler configuration:
<span class="line"><span class="nb-shiki-140thh">{</span></span>
<span class="line"><span class="nb-shiki-dzsirb"> "services"</span><span class="nb-shiki-140thh">: [</span></span>
<span class="line"><span class="nb-shiki-140thh"> {</span></span>
<span class="line"><span class="nb-shiki-dzsirb"> "binding"</span><span class="nb-shiki-140thh">: </span><span class="nb-shiki-mdbnqw">"PYTHON_RPC"</span><span class="nb-shiki-140thh">,</span></span>
<span class="line"><span class="nb-shiki-dzsirb"> "service"</span><span class="nb-shiki-140thh">: </span><span class="nb-shiki-mdbnqw">"py-rpc-server"</span></span>
<span class="line"><span class="nb-shiki-140thh"> }</span></span>
<span class="line"><span class="nb-shiki-140thh"> ]</span></span>
<span class="line"><span class="nb-shiki-140thh">}</span></span>
<span class="line"><span class="nb-shiki-140thh">[[</span><span class="nb-shiki-1t8gfj">services</span><span class="nb-shiki-140thh">]]</span></span>
<span class="line"><span class="nb-shiki-140thh">binding = </span><span class="nb-shiki-mdbnqw">"PYTHON_RPC"</span></span>
<span class="line"><span class="nb-shiki-140thh">service = </span><span class="nb-shiki-mdbnqw">"py-rpc-server"</span></span>
For more details on the announcement, read the blog post ↗.
For more information, refer to the Workers RPC documentation and the Python Workers overview.
Fetched August 3, 2026

