---
title: Foreign Function Interface (FFI)
description: Call JavaScript APIs, bindings, and globals from Python Workers using the Pyodide FFI.
image: https://edgetunnel-b2h.pages.dev/dev-products-preview.png
---

> Documentation Index  
> Fetch the complete documentation index at: https://edgetunnel-b2h.pages.dev/workers/llms.txt  
> Use this file to discover all available pages before exploring further. 

[Skip to content](#%5Ftop) 

# Foreign Function Interface (FFI)

Via [Pyodide ↗](https://pyodide.org/en/stable/), Python Workers provide a [Foreign Function Interface (FFI) ↗](https://en.wikipedia.org/wiki/Foreign%5Ffunction%5Finterface) to JavaScript. This allows you to:

* Use [bindings](https://edgetunnel-b2h.pages.dev/workers/runtime-apis/bindings/) to resources on Cloudflare, including [Workers AI](https://edgetunnel-b2h.pages.dev/workers-ai/), [Vectorize](https://edgetunnel-b2h.pages.dev/vectorize/), [R2](https://edgetunnel-b2h.pages.dev/r2/), [KV](https://edgetunnel-b2h.pages.dev/kv/), [D1](https://edgetunnel-b2h.pages.dev/d1/), [Queues](https://edgetunnel-b2h.pages.dev/queues/), [Durable Objects](https://edgetunnel-b2h.pages.dev/durable-objects/), [Service Bindings](https://edgetunnel-b2h.pages.dev/workers/runtime-apis/bindings/service-bindings/) and more.
* Use JavaScript globals, like [Request](https://edgetunnel-b2h.pages.dev/workers/runtime-apis/request/), [Response](https://edgetunnel-b2h.pages.dev/workers/runtime-apis/response/), and [fetch()](https://edgetunnel-b2h.pages.dev/workers/runtime-apis/fetch/).
* Use the full feature set of Cloudflare Workers — if an API is accessible in JavaScript, you can also access it in a Python Worker, writing exclusively Python code.

The details of Pyodide's Foreign Function Interface are documented [here ↗](https://pyodide.org/en/stable/usage/type-conversions.html), and Workers written in Python are able to take full advantage of this.

## Using Bindings from Python Workers

Bindings allow your Worker to interact with resources on the Cloudflare Developer Platform. When you declare a binding on your Worker, you grant it a specific capability, such as being able to read and write files to an [R2](https://edgetunnel-b2h.pages.dev/r2/) bucket.

For example, to access a [KV](https://edgetunnel-b2h.pages.dev/kv) namespace from a Python Worker, you would declare the following in your Worker's [Wrangler configuration file](https://edgetunnel-b2h.pages.dev/workers/wrangler/configuration/):

* [  wrangler.jsonc ](#tab-panel-12690)
* [  wrangler.toml ](#tab-panel-12691)

**JSONC**

```jsonc
{
  "main": "./src/index.py",
  "kv_namespaces": [
    {
      "binding": "FOO",
      "id": "<YOUR_KV_NAMESPACE_ID>"
    }
  ]
}
```

**TOML**

```toml
main = "./src/index.py"


[[kv_namespaces]]
binding = "FOO"
id = "<YOUR_KV_NAMESPACE_ID>"
```

...and then call `.get()` on the binding object that is exposed on `env`:

**Python**

```python
from workers import WorkerEntrypoint, Response


class Default(WorkerEntrypoint):
    async def fetch(self, request):
        await self.env.FOO.put("bar", "baz")
        bar = await self.env.FOO.get("bar")
        return Response(bar) # returns "baz"
```

### Converting Python to JavaScript

Occasionally, to interoperate with JavaScript APIs, you may need to convert a Python object to JavaScript. Pyodide provides a `to_js` function to facilitate this conversion.

**Python**

```python
from js import Object
from pyodide.ffi import to_js as _to_js


from workers import WorkerEntrypoint, Response


# to_js converts between Python dictionaries and JavaScript Objects
def to_js(obj):
   return _to_js(obj, dict_converter=Object.fromEntries)
```

For more details, see out the [documentation on pyodide.ffi.to\_js ↗](https://pyodide.org/en/stable/usage/api/python-api/ffi.html#pyodide.ffi.to%5Fjs).

## Using JavaScript globals from Python Workers

We recommend using the `workers` module, which is provided by our `workers-runtime-sdk` package, to access JavaScript globals in a more Pythonic way. However, if you need to access JavaScript globals directly for any reason, you can import them from the `js` module.

For example, note how `Response` is imported from `js` in the example below:

**Python**

```python
from workers import WorkerEntrypoint
from js import Response


class Default(WorkerEntrypoint):
    async def fetch(self, request):
        return Response.new("Hello World!")
```

Refer to the [Python examples](https://edgetunnel-b2h.pages.dev/workers/languages/python/examples/) to learn how to call into JavaScript functions from Python, including `console.log` and logging, providing options to `Response`, and parsing JSON.

```json
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://edgetunnel-b2h.pages.dev/workers/languages/python/ffi/#page","headline":"Work with JavaScript objects, methods, functions and globals from Python Workers · Cloudflare Workers docs","description":"Call JavaScript APIs, bindings, and globals from Python Workers using the Pyodide FFI.","url":"https://edgetunnel-b2h.pages.dev/workers/languages/python/ffi/","inLanguage":"en","image":"https://edgetunnel-b2h.pages.dev/dev-products-preview.png","dateModified":"2026-06-22","publisher":{"@type":"Organization","name":"Cloudflare","url":"https://www.cloudflare.com/"},"isPartOf":{"@type":"WebSite","@id":"https://edgetunnel-b2h.pages.dev/#website","name":"Cloudflare Docs","url":"https://edgetunnel-b2h.pages.dev/"}}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"/directory/","name":"Directory"}},{"@type":"ListItem","position":2,"item":{"@id":"/workers/","name":"Workers"}},{"@type":"ListItem","position":3,"item":{"@id":"/workers/languages/","name":"Languages"}},{"@type":"ListItem","position":4,"item":{"@id":"/workers/languages/python/","name":"Python Workers"}},{"@type":"ListItem","position":5,"item":{"@id":"/workers/languages/python/ffi/","name":"Foreign Function Interface (FFI)"}}]}
```
