# pocketbase for Python: the PocketBase client in Python

> The PocketBase Python SDK is a translation of the official JavaScript client rather than a redesign, built on HTTPX with a single runtime dependency. It keeps the API's own filter syntax, converts response keys to snake_case by default with an opt-out, and runs its integration tests against a real PocketBase instance downloaded at test time.

**vaphes/pocketbase** — PocketBase client SDK for python

- Repository: https://github.com/vaphes/pocketbase
- Website: https://pypi.org/project/pocketbase/
- Stars: 547 · Forks: 62
- Language: Python
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/vaphes-pocketbase

## A Python translation of the JavaScript client

The PocketBase Python SDK is a client for the PocketBase backend, and the README is candid about what it is at this stage: this is in early development, and at first is just a translation of the JavaScript library using HTTPX.

That single sentence sets expectations for the whole package. It is not a redesigned Python client with a different philosophy, it is the same client expressed in Python, and the guidance to users is to use it as you would use the JavaScript library but in a Pythonic way of course.

The philosophy is stated as a rule of thumb, and it is a good one to hold on to: when you are unsure how something should look, port the JavaScript call and then adjust it to the Python conventions.

The installation is one pip command:

```shell
python3 -m pip install pocketbase
```

The package is published on PyPI as pocketbase, and the version is 0.17.3 with the last push on 2026-05-20. The recent releases show a steady pace, 0.16.0 in April 2026 followed by 0.17.1 and 0.17.3 in May. The licence is MIT, and the project is on GitHub as vaphes/pocketbase.

The package metadata names two authors, Vithor Jaeger and Max Amling, and the project is distributed under MIT with the licence in a LICENCE.txt file at the root.

## The client surface, and how it reads

The usage example is the best description of the API shape, and it is short enough to read as a whole.

```python
from pocketbase import PocketBase  # Client also works the same
from pocketbase.client import FileUpload

client = PocketBase('http://127.0.0.1:8090')

# authenticate as regular user
user_data = client.collection("users").auth_with_password(
    "user@example.com", "0123456789")
# check if user token is valid
user_data.is_valid

# or as admin
admin_data = client.admins.auth_with_password("test@example.com", "0123456789")

# check if admin token is valid
admin_data.is_valid

# list and filter "example" collection records
result = client.collection("example").get_list(
    1, 20, {"filter": 'status = true && created > "2022-08-01 10:00:00"'})

# create record and upload file to image field
result = client.collection("example").create(
    {
        "status": "true",
        "image": FileUpload(("image.png", open("image.png", "rb"))),
    })

# and much more...
```

The structure is a client object with a collection method on it, and a separate admins namespace for the administrative API. You create the client with a base URL, then authenticate a regular user with collection("users").auth_with_password, or an admin with admins.auth_with_password, and both return an object with an is_valid property that tells you whether the token you hold is still usable.

That is the part worth pausing on, because checking token validity is something the JavaScript SDK makes you do and a Python SDK could have hidden. Here it stays visible as a property on the auth result, which is exactly the kind of small decision a translation preserves rather than improves.

Listing and filtering is a get_list call taking a page, a per page count and a filter string, so the filter syntax is the API's own, written as a string rather than as a builder. Creating a record with a file upload is a create call with a dictionary, and the file is a FileUpload tuple of a filename and an open binary file handle.

The import at the top shows the two entry points you are likely to use. PocketBase and Client are equivalent, the README notes that Client also works the same, and FileUpload comes from the client module.

More detailed API docs and copy-paste examples are in the API documentation for each service, and the instruction there is to just remember to pythonize it.

## snake_case by default, with an escape hatch

There is one behavioural difference from the JavaScript library that the README calls out with a note, and it is the kind of detail that causes quiet bugs if you miss it.

By default, camelCase, or any other key style, from the API is converted to snake_case in Python. So a field the API calls something like createdAt arrives in Python as created_at. That is the right default for a Python library, and it is also a difference from the JavaScript client that a ported snippet will not have accounted for.

The escape hatch is a constructor argument:

```python
from pocketbase import Client
client = Client(auto_snake_case=False)
# Fields will keep their original names from the API
```

Setting auto_snake_case to false when creating the client keeps the original key names from the API. So the two options are a Pythonic default and an opt-out for the cases where you need the raw API shape, such as when a field name is being passed through to something else unchanged.

That argument is on the client, not on individual calls, so it is a whole-session decision. That is the right place for it, since it affects every response, and it means switching back to the original naming is a matter of changing how the client is constructed rather than rewriting the code that reads the fields.

## The dependency set, and why there is only one runtime dependency

The project configuration is worth reading because it is unusually restrained.

```toml
dependencies = ["httpx>=0.27.2"]

[dependency-groups]
dev = [
    "pytest>=8.3.3",
    "pytest-httpx>=0.30.0",
    "ruff>=0.7.0",
    "coveralls>=4.0.1",
    "environs>=14.5.0",
]

[build-system]
requires = ["uv_build>=0.9.8,<0.12.0"]
build-backend = "uv_build"

[tool.ruff]
line-length = 80
```

There is exactly one runtime dependency, httpx at 0.27.2 or newer, and the README explains the choice: HTTPX is what the translation is built on, in place of whatever the JavaScript library uses natively.

The single dependency is a deliberate consequence of that decision. A client that mirrors an existing API does not need its own HTTP layer, so it uses the best-maintained async-capable one and inherits its behaviour, including its connection pooling and its transport configuration.

The development group is where the interesting choices are. pytest for the test runner, pytest-httpx for mocking HTTP responses so the tests do not need a live server, ruff for linting and formatting, coveralls for coverage reporting, and environs for reading configuration from the environment. The pytest-httpx dependency in particular tells you the unit tests are hermetic, with the HTTP layer mocked rather than a PocketBase instance being started.

Ruff is configured with a line length of 80 and a target version of py310, which matches the requires-python floor of 3.10 or newer. The classifiers list Python 3.10 through 3.14, so the package claims support for five interpreter versions.

The build backend is uv_build, with a version range on the requirement, and the repository carries a uv.lock file. The build tooling has moved to the uv ecosystem even though the README still documents Poetry for the development workflow, which is a small inconsistency worth noting if you are setting up a contribution environment.

## Integration tests against a real PocketBase

The testing story has two halves, and the second is the more interesting one.

The unit tests run with pytest, and the command is a single line. But the integration tests need something running.

The README explains the arrangement: a lot of real-world integration tests against a sandboxed PocketBase instance will be included in the pytest when the sandbox is running, on 127.0.0.1:8090. To start it, you follow the steps in the sandbox block:

```bash
export TMP_EMAIL_DIR=`mktemp -d`  # Export temp dir used for sendmail sandbox
bash ./tests/integration/pocketbase     # Run the pocketbase sandbox (automatically downloads the latest pocketbase instance)
pytest  # Run test including sandbox API integration tests
```

Three commands, and each one does something specific. The first exports a temporary directory used for the sendmail sandbox, which is what lets the test suite exercise the email-sending endpoints without sending real mail. The second runs the sandbox script from the tests/integration directory, and the comment notes that it automatically downloads the latest PocketBase instance. The third runs pytest, which now includes the sandbox API integration tests because the instance is up.

Downloading the server binary at test time is a choice with consequences. It means the tests exercise a real PocketBase rather than a mock of one, so the contract between this SDK and the server is verified against the actual implementation rather than against the SDK author's idea of it. It also means the test run needs network access and that the behaviour tested is whatever the latest server does, which can change underneath a release of the client.

The hybrid is sensible. pytest-httpx handles the cases where you want to assert on a specific error shape or a specific header without standing up anything, and the sandbox handles the cases where the round trip is the thing being tested.

The development requirements are Python 3.9 or newer and Poetry, and there are two ways to install locally, poetry install or python3 -m pip install -e . if you are only using pip. The tests are also covered by CI, with a tests workflow badge, and coverage is reported to Coveralls with a badge on the master branch.

## Conclusion

The PocketBase Python SDK suits a project that already has a PocketBase backend and wants a client that behaves like the documented JavaScript one, since the translation approach means the API surface is predictable and the upstream documentation applies almost directly. It does not suit you if you want a Python client designed around Python idioms, because the README says the opposite explicitly. Before you adopt it, note that it is described as in early development, so the version you pin matters, and remember that the default snake_case conversion changes every field name from the API, so existing snippets will need adjusting or the auto_snake_case flag will need turning off.

## FAQ

### How do I install and start using the PocketBase Python SDK?

Run python3 -m pip install pocketbase. Then create a client with PocketBase('http://127.0.0.1:8090'), and authenticate with client.collection("users").auth_with_password for a regular user or client.admins.auth_with_password for an admin, and check the is_valid property on the result.

### How do I stop the PocketBase SDK from converting API keys to snake_case?

Pass auto_snake_case=False when creating the client, for example Client(auto_snake_case=False). By default camelCase and other key styles from the API are converted to snake_case in Python, and the option keeps the original field names.

### How do I upload a file with the PocketBase Python SDK?

Import FileUpload from pocketbase.client and pass a tuple of the filename and an open binary file handle in the record data, for example "image": FileUpload(("image.png", open("image.png", "rb"))). The create call takes that dictionary along with the other field values.

### How do I run the PocketBase SDK integration tests?

Start the sandbox first. Export a temporary email directory with mktemp, run bash ./tests/integration/pocketbase which automatically downloads the latest PocketBase instance, and then run pytest, which includes the sandbox API integration tests when the instance is up on 127.0.0.1:8090.

## Sources

- [License: MIT](https://github.com/vaphes/pocketbase/blob/master/LICENSE)
- [Project website](https://pypi.org/project/pocketbase/)
- [README](https://github.com/vaphes/pocketbase/blob/master/README.md)
- [Releases](https://github.com/vaphes/pocketbase/releases)
- [vaphes/pocketbase on GitHub](https://github.com/vaphes/pocketbase)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/vaphes-pocketbase
