Skip to main content

ZeroBucket

PyPI version Python versions License: MIT CI

Your database. Your images. Zero buckets.

ZeroBucket is a database-native image storage library. It lets you store and retrieve images using the PostgreSQL database you already have, instead of standing up a separate object-storage service like S3.

from zerobucket import ZeroBucket

images = ZeroBucket(database_url="postgresql://...")

image_id = images.put("avatar.jpg")

image = images.get(image_id)
print(image.mime_type)   # "image/jpeg"
print(image.size_bytes)  # 1116478
print(image.data)        # raw bytes, ready to serve

Full documentation, architecture notes, and benchmark results live in the GitHub repository.

Installation

pip install zerobucket

Requires Python 3.10+ and PostgreSQL 13+ (uses gen_random_uuid(), built in since Postgres 13).

Quick reference

Method What it does
images.put(image, filename=None) Validates, checksums, and stores an image. Accepts a file path, raw bytes, or a file-like object (including framework upload objects). Returns the new image's id.
images.get(image_id) Returns an Image (data, mime_type, filename, width, height, size_bytes, checksum_sha256). Raises ImageNotFoundError if missing.
images.metadata(image_id) Same fields as get() but without the raw bytes — cheap existence/info check.
images.exists(image_id) Returns True/False.
images.delete(image_id) Deletes the image. Returns True if it existed.
images.close() Releases database connections. ZeroBucket also works as a context manager.
from zerobucket import ZeroBucket, ImageNotFoundError, ImageValidationError

images = ZeroBucket(
    database_url="postgresql://user:pass@localhost/mydb",
    max_bytes=8 * 1024 * 1024,  # default: 8MB
)

image_id = images.put("photo.jpg")
image_id = images.put(open("photo.jpg", "rb"))
image_id = images.put(request.files["avatar"])  # framework upload objects

image = images.get(image_id)
info = images.metadata(image_id)

try:
    images.get("nonexistent-id")
except ImageNotFoundError:
    ...

try:
    images.put("not-actually-an-image.txt")
except ImageValidationError:
    ...

Serving from a web API

from flask import Flask, Response

app = Flask(__name__)
images = ZeroBucket(database_url=DATABASE_URL)

@app.route("/images/<image_id>")
def serve_image(image_id):
    image = images.get(image_id)
    return Response(image.data, mimetype=image.mime_type)

What it validates

  • Format: JPEG, PNG, WebP — detected from actual file content, never from filename extension or a client-supplied Content-Type header.
  • Corruption: truncated or malformed images are decoded and rejected before they reach the database.
  • Decompression bombs: a tiny compressed file that decodes to an enormous pixel grid is rejected, not silently allocated.
  • Size: configurable via max_bytes (default 8MB) — see the benchmark results for why.

Limitations (read before using in production)

  • Not built for large files or high-volume media. Full images are read into memory on both ends of every request — no streaming, no range requests, no CDN.
  • No deduplication yet. A SHA-256 checksum is stored on every row, but duplicate uploads currently create duplicate rows.
  • No resize/optimization pipeline yet. ZeroBucket validates and stores what you give it; it doesn't transform it.
  • PostgreSQL only, for now. The storage layer is abstracted for future adapters, but only Postgres exists today.

See the full README and roadmap on GitHub for more detail, including why BYTEA storage doesn't compress image bytes any further than they already are.

License

MIT — see LICENSE.

Release files for zerobucket 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for zerobucket 0.1.1
File Size Uploaded
zerobucket-0.1.1.tar.gz 12.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for zerobucket 0.1.1
File Interpreter ABI Platform
zerobucket-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 24.4 kB

Release files / zerobucket-0.1.1.tar.gz

Download URL zerobucket-0.1.1.tar.gz
Size 12.2 kB
Tags Source
SHA-256 checksum
How to use checksums
2f2e99841cc8c07c2fa091251e37c92a94c9958450a6c798efb483ade8d07d91
BLAKE2b-256 checksum
How to use checksums
701a724a8b2679e10fa98730b1560b622c9d45f006ade135716e0bb07b009f3f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.9

Release files / zerobucket-0.1.1-py3-none-any.whl

Download URL zerobucket-0.1.1-py3-none-any.whl
Size 12.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
082f346b254da34470092243c7aa1fcf119e6e85af71413593f2b40b730c133c
BLAKE2b-256 checksum
How to use checksums
61d5127dc29b970930ee14427ed4b9c55ba978e3cc3a8eee5272ba28be4a4b9e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.9

Release history Release notifications | RSS feed

0.21.0

2 release files

0.20.0

2 release files

0.18.0

2 release files

0.17.0

2 release files

0.16.0

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page