spatie/laravel-db-snapshots
Spatie's Laravel package adding Artisan commands to instantly dump and load MySQL, PostgreSQL, or SQLite databases. Create named snapshots, load the latest, list, and clean up old dumps in seconds.
Architecture fit
The package is a thin Laravel-native wrapper: it registers a service provider, exposes six Artisan commands (snapshot:create, :load, :list, :delete, :cleanup, plus --latest/--table/--exclude/--compress/--stream/--drop-tables flags), and delegates the actual work to spatie/db-dumper, which in turn shells out to mysqldump, pg_dump, or sqlite3. That delegation is the single most important architectural fact. This is not a backup engine — it is a developer-experience facade over vendor CLI tools, with Laravel's filesystem abstraction layered on for storage and Laravel's config/database.php used as the credential source.
The fit is therefore narrow and specific: it is an excellent fit for developer and CI workflows (seeding local/staging environments from a known dump, resetting a test database between suites, snapshot-before-migration safety nets, handing a reproducible dataset to QA) and a poor primary fit for production disaster recovery, where you need point-in-time recovery, integrity verification, encryption, cross-region replication, and a restore SLA. Treating it as a DR solution is the most likely way a team misadopts this package. It is architecturally a sibling of django-dbbackup or a bin/dump shell script — not of RDS automated backups or pgBackRest.
Integration feasibility
Low friction on the happy path: composer require spatie/laravel-db-snapshots, add a snapshots disk to config/filesystems.php, optionally publish the config. Everything is driven by Artisan, so it slots into existing deployment scripts, Composer scripts, Pest/PHPUnit setUp, and Laravel's scheduler with no glue code. The event surface (CreatingSnapshot, CreatedSnapshot, LoadingSnapshot, LoadedSnapshot, DeletingSnapshot, DeletedSnapshot) is the main extension seam and is sufficient for audit logging and Slack/observability hooks without forking.
The real integration cost is environmental, not code: the target host must have the matching DB client binaries installed and on PATH, plus a writable temporary_directory_path. This is trivial on a developer laptop or a standard VM-based CI runner and non-trivial in distroless containers, Laravel Vapor/Lambda, or locked-down PaaS buildpacks. Any integration plan must resolve "where do the binaries come from" before writing a line of config.
Technical risk
mysqldump and pg_dump must generally be at or above the server major version. Container base images drift; managed database engines auto-upgrade. This is the highest-probability silent failure.snapshot:load drops all tables unless --drop-tables=0 is passed. A mistyped connection name can wipe the wrong database. This is the highest-severity risk and needs guardrails (environment checks, APP_ENV gating, confirmation prompts in wrapper commands).--stream mitigates this but the changelog shows recent fixes (2.9.0) for chunk-boundary and continued-line parsing bugs, which signals the streaming path is newer and less battle-tested.database_path('snapshots') — the documented default — the files live inside the deploy directory, are commonly ephemeral in containers, and are one missing .gitignore entry away from being committed. PII in a .sql file on local disk is a compliance finding waiting to happen.config/database.php, so whatever privilege the app's DB user has, the dump has. There is no separate backup role, no read-replica targeting, and no IAM/Cloud SQL connector story documented beyond the connect_via_database support added in 2.5.0.Key questions
mysqldump/pg_dump/sqlite3, or is it serverless/distroless?--stream hold up at that size?snapshot:load against a shared or production-like database, and how is that enforced?Stack fit
Strong fit for standard Laravel monoliths on VM/container infrastructure running MySQL, MariaDB, PostgreSQL, or SQLite — all four are supported, with MariaDB support added in 2.6.1. Weak fit for serverless Laravel (Vapor) and for polyglot estates where non-PHP services also need the data, since everything here is only reachable through Artisan. If the org is Laravel-standardized on current versions, fit is effectively native.
Migration path
Adopt incrementally rather than as a replacement. Phase one: install as a developer convenience only, on local and CI environments, with the snapshots disk pointed at storage_path() rather than database_path() and added to .gitignore. This delivers the productivity win with zero production blast radius. Phase two: add a scheduled snapshot:create --compress job in staging with snapshot:cleanup --keep=N chained after it, giving a lightweight "restore staging to yesterday morning" capability. Phase three — only if a genuine gap is confirmed — extend to production, and only via a wrapper command that enforces environment checks, uses a dedicated low-privilege backup connection configured under default_connection, writes to a remote Flysystem disk with server-side encryption, and fires CreatedSnapshot into the existing monitoring pipeline. Do not decommission any incumbent backup tooling on the strength of this package.
Compatibility
Actively maintained across Laravel majors through 13 (per changelog 2.8.0/2.7.1/2.6.0), PHP 8.x on v2, PHP 7.x/Laravel 6.x requires pinning v1.x. Pin the major version in composer.json and track the spatie/db-dumper constraint (v4 allowed as of 2.10.0), because dumper upgrades can change CLI flag behavior. The dump.addExtraOption connection key (e.g. --no-owner for Postgres) is the escape hatch for engine-specific quirks and should be documented as the sanctioned customization point rather than patching the package.
Sequencing
.gitignore and disk-path fixes.Maintenance
Ongoing cost is low but not zero. The package itself is small and stable; the maintenance burden is concentrated in the environment (client binary versions tracking server upgrades) and in the storage lifecycle (unbounded dump accumulation is the classic failure — snapshot:cleanup --keep=N exists but is opt-in and must be scheduled, not assumed). Budget a recurring check that CI base images ship a pg_dump/mysqldump at or above the managed database's major version; that one check prevents most incidents.
Support
MIT-licensed, Spatie-maintained, high-reputation vendor with a broad package portfolio and an active changelog (recent releases include Laravel 13 support and two correctness fixes to streamed loading). Documentation is a README and CHANGELOG — good for the happy path, thin on troubleshooting. There is no commercial SLA. Support burden therefore falls internally: name an owner, write a runbook covering "restore staging from snapshot," and document the --stream/--drop-tables flags prominently. Because the package is a thin wrapper, most "package bugs" will actually be binary-version or permissions issues — the runbook should route there first.
Scaling
Scales acceptably with data volume up to the point where full-dump duration and storage exceed the maintenance window and disk budget; --compress and --stream extend that range but do not eliminate it. Does not scale as a many-database fleet management tool — there is no inventory, no parallel orchestration, no central catalog across applications. Per-app scheduling via Laravel's scheduler is fine for a handful of apps, not for dozens. Storage scaling is a matter of the configured Flysystem disk; S3-backed snapshots work but restore latency becomes network-bound.
Failure modes
Ranked by expected pain: (1) silent partial restore after an interrupted load — no atomicity, so verify row counts post-restore; (2) accidental drop of the wrong database via a misdirected --connection combined with the default --drop-tables behavior; (3) binary version mismatch producing a dump that fails to load or, worse, loads incompletely; (4) OOM/timeout on large unstreamed loads; (5) disk exhaustion from unscheduled cleanup; (6) snapshot files left inside the deploy directory and lost on redeploy, or committed to version control; (7) plaintext PII exposure on the snapshots disk. Each maps to a specific control: post-restore verification, environment gating, image-pinned client versions, --stream as default, scheduled cleanup, explicit disk path + .gitignore, and encryption/lifecycle policy on the target disk.
Ramp-up
Very fast for engineers already fluent in Artisan — the commands are self-documenting and the README is five minutes of reading. Expect near-zero ramp-up for the create/list/load loop and roughly a day of institutional learning for the sharp edges (drop semantics, streaming, binary dependencies, storage hygiene). The larger ramp-up cost is organizational, not technical: getting the team to agree on what this tool is for so it is not mistaken for a backup-of-record, and establishing the guardrails that keep a destructive load command out of unauthorized hands. That framing conversation is the TPM's actual deliverable here.
How can I help you explore Laravel packages today?