How to configure S3 blob tiering#
This guide shows you how to configure tiered blob storage so that small blobs stay in PostgreSQL and large blobs go to S3.
Install the S3 extra#
pip install zodb-pgjsonb[s3]
# or
uv pip install zodb-pgjsonb[s3]
This installs the zodb-s3blobs dependency with the boto3 S3 client.
Add S3 configuration to ZConfig#
Add the S3 keys to your <pgjsonb> section in zope.conf:
%import zodb_pgjsonb
<zodb_db main>
<pgjsonb>
dsn dbname=zodb user=zodb host=localhost port=5432
s3-bucket-name my-zodb-blobs
s3-region us-east-1
s3-prefix production/
blob-threshold 100KB
blob-cache-dir /var/cache/zodb-blobs
blob-cache-size 1GB
</pgjsonb>
</zodb_db>
S3 configuration keys#
Key |
Default |
Description |
|---|---|---|
|
none |
S3 bucket name (setting this enables S3 tiering) |
|
none |
AWS region name |
|
none |
S3 endpoint URL (for MinIO, Ceph, or other S3-compatible stores) |
|
none |
AWS access key ID (uses boto3 credential chain if omitted) |
|
none |
AWS secret access key (uses boto3 credential chain if omitted) |
|
|
Enable SSL for S3 connections |
|
empty |
S3 key prefix for namespace isolation |
Blob storage keys#
Key |
Default |
Description |
|---|---|---|
|
|
Blobs larger than this go to S3 |
|
auto |
Local cache directory for S3 blobs |
|
|
Maximum size of the local blob cache |
Choose a blob-threshold strategy#
The blob-threshold setting controls how blobs are distributed between PostgreSQL and S3.
PG-only mode (no S3):
Omit s3-bucket-name entirely.
All blobs stay in PostgreSQL bytea columns regardless of size.
Tiered mode (default with S3):
Set blob-threshold to a size like 100KB (the default).
Blobs smaller than this stay in PostgreSQL for fast access.
Blobs at or above this threshold go to S3.
S3-only mode:
Set blob-threshold to 0.
All blobs go to S3, keeping the PostgreSQL database compact.
Set up a local blob cache#
Set blob-cache-dir to a local directory for caching S3 blobs on disk.
This avoids repeated S3 downloads for frequently accessed blobs.
Set blob-cache-size to the maximum disk space for the cache.
The cache uses LRU eviction when the limit is reached.
For production, always configure a blob cache directory to reduce S3 latency and cost.
Use MinIO for development#
Start a MinIO container:
docker run -d --name minio \
-p 9000:9000 -p 9001:9001 \
-e MINIO_ROOT_USER=minioadmin \
-e MINIO_ROOT_PASSWORD=minioadmin \
minio/minio server /data --console-address ":9001"
Create a bucket:
mc alias set local http://localhost:9000 minioadmin minioadmin
mc mb local/zodb-blobs
Configure the storage to use MinIO:
<pgjsonb>
dsn dbname=zodb user=zodb host=localhost port=5432
s3-bucket-name zodb-blobs
s3-endpoint-url http://localhost:9000
s3-access-key minioadmin
s3-secret-key minioadmin
s3-use-ssl false
blob-threshold 100KB
</pgjsonb>