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>