zenstruck/backup
A simple, configurable backup package for Laravel that archives your application’s database and files, stores backups on any Laravel filesystem disk, and integrates with the scheduler for automated backups.
Architecture fit
zenstruck/backup is a framework-agnostic PHP library, not a Laravel package. It has no service provider, no publishable config, no facade, and no scheduler or queue awareness. That is not a defect — it is a positioning issue. It fits as a low-level primitive inside a backup pipeline we own (compose an archive, hand it to a destination), not as a drop-in replacement for the incumbent (spatie/laravel-backup), which is opinionated, Laravel-native, and battle-tested. The realistic architectural frame is: we build a thin Laravel wrapper (command + config + scheduling + notifications + retention) on top of this library, and the library only owns archive creation and destination writes. Any evaluation that assumes "install and configure" is wrong; the wrapper is the product, and the dependency is a component.
Integration feasibility
High on mechanics, moderate on total effort. Composer install, MIT license, one dependency, small public surface — the integration cost is concentrated in the work we would do anyway (Artisan command, config file, Storage disk mapping, schedule entry, failure alerting), not in fighting the library. The genuine integration questions are behavioral: how it streams large archives (memory ceiling vs. temp-disk), whether destinations are pluggable enough to bind Laravel's Flysystem disks, whether it can drive database dumps or only file trees, and whether it shells out to tar/mysqldump/pg_dump.
Technical risk
proc_open enabled, writable temp space). This is the most common way backup tooling fails silently in production.Key questions to resolve before committing
mysqldump/pg_dump ourselves?Stack fit
Good fit at the component level: PHP 8.x, Composer, no framework lock-in, so it sits cleanly under a Laravel 10–12 application. The wrapper we write should map its output to Laravel Storage disks (Flysystem v3, S3/GCS/local), expose a backup:run Artisan command, register a backup:clean retention command, and register both on Schedule::command(...) with withoutOverlapping() and onOneServer(). Long runs should be dispatchable to a queue worker with an extended timeout, with the command also runnable synchronously for cron-based deployments.
Migration path
Assume an incumbent (custom cron + shell scripts, or spatie/laravel-backup). Do not rip it out.
Compatibility checks to gate on PHP constraint vs. our runtime matrix; absence of native Laravel support (we supply it, so no version-lag risk from the library itself); Flysystem adapter compatibility; DB driver coverage; behavior on Windows dev machines vs. Linux containers (if developers cannot run it locally, restore drills will not happen); filesystem permissions for temp archives.
Sequencing Library spike → restore drill (prove recoverability before proving backup) → wrapper package (config, commands, scheduling) → observability (success/failure events, artifact-age metric, alerting) → retention and encryption → pilot service → fleet rollout. The restore drill must precede the rollout; a backup you have not restored is a hypothesis.
Maintenance Low code volume, but nonzero ownership: we maintain the wrapper, and we absorb the risk of an upstream with a single maintainer and no visible dependent base. Budget a recurring line item — roughly a few engineer-days per quarter for version review, dependency bumps, and restore drills — plus a documented fork contingency (the MIT license makes vendoring viable; the cost is that we then own the library, not just the wrapper).
Support Ownership must be explicit; "the backup job" with no named owner is how silent failures persist for months. Deliverables: a runbook covering manual run, artifact location, restore procedure with expected RTO, and escalation. Alerting should be on artifact freshness and restore-drill success, not on job exit codes alone — exit-code alerting misses the case where the job "succeeds" and writes a truncated archive.
Scaling
Three pressures: (1) data volume vs. backup window — large datasets need incrementals or per-tenant sharding, which this library likely does not provide; (2) storage growth — retention/pruning must be ours, and S3 lifecycle rules are a cheaper lever than application logic; (3) concurrency — parallel backups contend for I/O and DB locks, so schedule staggering and withoutOverlapping are mandatory, not optional. Validate the memory/streaming profile early; it determines whether this scales past a few gigabytes at all.
Failure modes to design against
proc_open disabled in a container → immediate, loud failure (preferred).Ramp-up Small. The library's API is narrow enough that a mid-level engineer is productive in a day; the wrapper is a one-to-two-week build for a single engineer familiar with Laravel's scheduler, queue, and filesystem. The real ramp-up cost is organizational, not technical: teaching the team the restore runbook and establishing the drill cadence. Estimate 2–3 engineer-weeks end-to-end including the dual-run period.
TPM recommendation: viable as a component in an internal backup pipeline where we own the wrapper and the runbook, contingent on the spike proving streaming behavior, restore correctness, and destination flexibility. Not viable as a turnkey Laravel backup solution, and not appropriate as the sole recovery mechanism for tier-0 data without a fork contingency and a rehearsed restore process.
How can I help you explore Laravel packages today?