Dumpling

Documentation

Everything you need to know to run Dumpling with confidence. If something is missing, email support.

How it works

A Dumpling backup job connects one database to one storage destination on a schedule. When a job is due, our worker opens a connection to your database, runs the native dump tool, and streams the output through memory directly into your bucket using S3 multipart upload. No temporary files are created and we do not retain a copy.

Objects are named by UTC timestamp inside a folder per job, for example backups/production-db/2026-09-10T02-00-01Z.dump, so they sort chronologically in any bucket browser.

Connecting a database

Your database must be reachable from the public internet from our worker's IP address:

2.28.121.200

Allow-list that address in your provider's firewall or trusted-sources list. We recommend a dedicated read-only user:

-- PostgreSQL
CREATE ROLE dumpling LOGIN PASSWORD 'strong-password';
GRANT CONNECT ON DATABASE app TO dumpling;
GRANT USAGE ON SCHEMA public TO dumpling;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO dumpling;
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO dumpling;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO dumpling;

-- MySQL
CREATE USER 'dumpling'@'%' IDENTIFIED BY 'strong-password';
GRANT SELECT, SHOW VIEW, TRIGGER, LOCK TABLES, EVENT ON app.* TO 'dumpling'@'%';
-- Only if you want stored procedures/functions in the dump (otherwise they are skipped with a note):
GRANT SHOW_ROUTINE ON *.* TO 'dumpling'@'%';          -- MySQL 8.0.20+
GRANT SELECT ON mysql.proc TO 'dumpling'@'%';         -- MariaDB and MySQL 5.7

Platform-specific instructions for Railway, Render, Supabase, Neon, Fly.io, Heroku, DigitalOcean, Hetzner, RDS and PlanetScale are in the guides.

Storage destinations

Any S3-compatible object store works. Create credentials that are scoped to one bucket with permission to put, get, list and delete objects. Retention needs delete permission; if you prefer to manage retention with bucket lifecycle rules, set "keep last" to 0 and grant write-only access.

Cloudflare R2 in five minutes

R2 is the storage we recommend when you have no bucket yet: the first 10 GB a month are free and there is no egress charge, so restores cost nothing. You need a Cloudflare account; the free plan is enough.

  1. In the Cloudflare dashboard open R2 Object Storage and click Create bucket. Name it something like db-backups, leave the location on Automatic, create it.Cloudflare's Create a bucket form with the name db-backups and location Automatic
  2. Go back to the R2 overview and open Manage R2 API Tokens โ†’ Create API token. Permissions: Object Read & Write. Under "Specify bucket(s)" pick the bucket you just created, nothing else. TTL: forever, or a date you will remember to rotate. Create it.Cloudflare's Create Account API Token form with Object Read & Write selectedThe Specify bucket(s) section with Apply to specific buckets only selected
  3. Cloudflare shows the Access Key ID, the Secret Access Key and the S3 endpoint, https://<accountid>.r2.cloudflarestorage.com, once. Keep the tab open.
  4. In Dumpling, Storage โ†’ Add storage โ†’ preset Cloudflare R2. Paste the bucket name, the endpoint, the two keys; region stays auto. The connection test writes and deletes one small object, so a wrong token fails here, not at 02:00.Dumpling's Add storage form with the Cloudflare R2 preset, endpoint and bucket filled in

The token can only touch that one bucket. Everything else in your Cloudflare account stays out of reach, which is the point of scoping it.

Restoring

Restore on purpose before you have to: the restore drill checklist is one page.

PostgreSQL

# download the file from your bucket, then:
createdb restored_db
pg_restore --no-owner --no-acl -d restored_db 2026-09-10T02-00-01Z.dump

# inspect contents without restoring:
pg_restore --list 2026-09-10T02-00-01Z.dump

Use a pg_restore from PostgreSQL 18 or newer: the archives are written by an 18 client, and an older pg_restore refuses them with "unsupported version in file header". On macOS brew install postgresql@18; otherwise the postgres:18 Docker image has one.

MySQL

mysql -e "CREATE DATABASE restored_db"
gunzip < 2026-09-10T02-00-01Z.sql.gz | mysql restored_db

Dumps are taken with the MariaDB client, which works against MySQL 5.7, 8.x and MariaDB. If an old mysql client rejects the first line of the file (the MariaDB sandbox-mode comment), drop it:

gunzip < 2026-09-10T02-00-01Z.sql.gz | sed '1{/999999/d}' | mysql restored_db

Encrypted backups

If a job has a passphrase, files end in .enc and are encrypted with AES-256-CBC in OpenSSL's standard format. You do not need Dumpling to decrypt them:

openssl enc -d -aes-256-cbc -pbkdf2 -in backup.dump.enc -out backup.dump -pass pass:'your-passphrase'

We cannot recover a lost passphrase. Store it in your password manager.

Alerts

Failures always email the notification address on your account. Every plan, Free included, can also post to a Slack or Discord channel: paste the incoming-webhook URL under Alerts. Any other HTTPS endpoint receives the same JSON payload; it includes a text field, so Slack and Discord render it directly. Successful runs can optionally notify too.

Security

The full picture, including what we never store and how to report a vulnerability, is on the security page.

Restore verification

While a backup streams, the dump the tool produced is checked before compression and encryption: for PostgreSQL, pg_restore --list must read the archive and list its contents; for MySQL, the dump must carry mysqldump's completion trailer. A run shows "verified" when that passed. When it does not, the run fails and you get the usual failure alert: an archive the restore tool rejected is deleted, like a dump that died, and no older backup is deleted on that run. If our side could not run the check at all, the file is kept and the alert says so. An empty database is a valid archive with nothing in it and counts as verified. It proves the dump tool emitted a complete, well-formed archive that the standard tools accept; it does not restore it into a database and does not re-read the uploaded object, so do your own restore drill occasionally.

Limits

Each plan has a maximum database size per backup (measured before every run) and a minimum schedule interval. Runs exceeding the limit fail with a clear message rather than silently producing a partial backup.

FAQ

Does Dumpling support MongoDB, Redis or SQLite?

No. Dumpling backs up PostgreSQL and MySQL/MariaDB only.

Can I back up multiple databases on one server?

Yes โ€” add each database separately. Each counts as one job.

My database is only reachable inside a private network.

Expose it through an SSH tunnel host, a Tailscale Funnel, or a Cloudflare Tunnel with the worker IP allow-listed. Dumpling does not open SSH tunnels itself.