Storage and the database
Paprika keeps its records in PostgreSQL and the bytes they describe on the data volume. Both are needed: a backup of one without the other can’t be restored.
PostgreSQL
Section titled “PostgreSQL”The API, the workers and the one-off services connect with PAPRIKA_DATABASE_URL. The Compose file runs PostgreSQL 18 in the db service, with its files in the db volume; to use a database server of your own, point PAPRIKA_DATABASE_URL at it and leave the db service out.
The schema is brought up to date by the migrate command, which the Compose file runs before the API starts. Migrations only ever move forward, and take a lock so that two at once can’t collide. An API whose database is behind its schema answers /ready with 503 until it has been migrated.
Paprika makes a database role of its own, paprika_app, and runs every tenant’s queries as it, so that the database itself keeps tenants apart (security). The user in PAPRIKA_DATABASE_URL needs the rights to create that role and the tables: the owner of the database.
The data volume
Section titled “The data volume”PAPRIKA_STORAGE=disk keeps the bytes under PAPRIKA_STORAGE_DIR, /data in the image: uploaded fonts, images and colour profiles, template packages, records files for batches and finished outputs, each under tenants/<tenant>/. The api and every worker must share it.
How long things are kept
Section titled “How long things are kept”An hourly sweep, run by one API at a time, removes what is past its time:
| What | Kept | Setting |
|---|---|---|
| Uploaded fonts, images and profiles | 30 days since last used | the tenant’s retentionDays (admin API) |
| Outputs (rendered files) | 24 hours | PAPRIKA_OUTPUT_RETENTION_HOURS |
| Finished jobs, batches and their records | 7 days | PAPRIKA_JOB_RETENTION_DAYS |
| Webhook deliveries | 7 days | PAPRIKA_JOB_RETENTION_DAYS |
| The audit log | 400 days | |
| Usage events and storage measures | 400 days, also past their tenant’s deletion, for its last bill | PAPRIKA_USAGE_KEEP_DAYS |
| A deleted tenant | 30 days, while it can be restored; then every row and file of it is purged | |
| Templates and their versions | until deleted |
A tenant’s library fonts and named resources stay while it has them.
Backups
Section titled “Backups”Back up the database and the data volume together, the database first: a file the database doesn’t list is harmless, a listed file that’s missing is not. With the Compose file:
docker compose exec db pg_dump -U paprika -Fc paprika > paprika.dumpdocker run --rm -v paprika_data:/data -v "$PWD":/backup busybox tar czf /backup/paprika-data.tgz -C /data .The keys volume needs no backup: editor-key issues a new key when the old one no longer works.
Limits
Section titled “Limits”What one request may send is limited, to keep a single tenant from tying up the service:
| Limit | Default | Setting |
|---|---|---|
| A template package | 100 MB | PAPRIKA_MAX_PACKAGE_MB |
| A package, unpacked | 250 MB | PAPRIKA_MAX_EXPANDED_MB |
| An image, in pixels | 40 megapixels | PAPRIKA_MAX_IMAGE_MEGAPIXELS |
| Jobs queued or running per tenant | 1,000 | PAPRIKA_MAX_QUEUED_JOBS |
| Records in a batch | 10,000 | PAPRIKA_MAX_BATCH_RECORDS |
| Batches open per tenant | 10 | PAPRIKA_MAX_OPEN_BATCHES |
| Records merged into one PDF | 1,000 | PAPRIKA_MAX_MERGED_RECORDS |
| A batch’s combined output | 1,000 MB | PAPRIKA_MAX_COMBINED_MB |
The configuration reference lists them all.