Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Db Snapshots Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package, register a disk, then run a snapshot in under five minutes:

composer require spatie/laravel-db-snapshots

Add a snapshots disk in config/filesystems.php — this is the one required configuration step. If the disk doesn't exist, every command fails:

'disks' => [
    'snapshots' => [
        'driver' => 'local',
        'root' => database_path('snapshots'),
    ],
],

Then create, mutate, and restore:

php artisan snapshot:create before-import
# ... run a migration, import, or fuzz the DB ...
php artisan snapshot:load before-import

First things to read in the repo: the README's Usage section (the actual surface area is ~8 artisan commands), the published config/db-snapshots.php, and src/Events/* if you plan to hook into the lifecycle. The package is a thin wrapper around spatie/db-dumper, so anything the underlying mysqldump/pg_dump/sqlite3 supports is reachable via the dump.addExtraOption connection key.

Publish the config as soon as you go beyond local dev:

php artisan vendor:publish --provider="Spatie\DbSnapshots\DbSnapshotsServiceProvider"

First real use case: seed a known-good local state before a risky migration, then reload it when the migration misbehaves. The second is snapshot:load --latest as a "reset to yesterday" button in staging.

Implementation Patterns

Point the disk at cloud storage for shared/shared-stage snapshots. Because snapshots go through Laravel's filesystem abstraction, swapping local for s3 gives you a team-shared snapshot store with zero code changes. Keep the temp directory on fast local disk (temporary_directory_path), though — the dump is written there first and then moved to the disk.

Compress by default in config, not per-command. 'compress' => true in the config means every snapshot is .sql.gz, which matters a lot once dumps exceed a few hundred MB. Remember to use --stream when loading large compressed files:

php artisan snapshot:load --latest --stream

Restore into a different connection for safe inspection. A very common workflow is dumping production-ish data and restoring it into a scratch connection rather than blowing away your dev DB:

php artisan snapshot:create prod-readonly --connection=production
php artisan snapshot:load prod-readonly_2026-01-15 --connection=scratch --drop-tables=1

Note the naming quirk: passing --connection without a name prepends the connection to an auto-generated timestamp name (logging_2017-03-17 14:31), so snapshot:list output is self-documenting. If you supply a name, no prefix is added.

Table-scoped snapshots for fixtures. --table and --exclude accept repeats or comma lists. Use --table for a small fixture set (reference data, CMS seed content) and --exclude when you want everything except huge log/telescope/jobs tables:

php artisan snapshot:create reference-data --table=countries,currencies,tax_rates
php artisan snapshot:create weekly --exclude=telescope_entries,jobs,failed_jobs,sessions

If both are passed, --table wins and --exclude is silently ignored — deliberately never pass both.

Schedule cleanups and creations. snapshot:cleanup --keep=N is a natural fit for the scheduler:

$schedule->command('snapshot:create nightly --compress')->dailyAt('02:00');
$schedule->command('snapshot:cleanup --keep=7')->dailyAt('02:30');

This gives you a rolling 7-day retention without writing a single line of backup logic.

Hook lifecycle events for observability. All six events carry the snapshot object, so you can log to Slack, push a metric, or copy the file off-disk after creation:

Event::listen(CreatedSnapshot::class, function ($event) {
    Log::info('snapshot created', ['name' => $event->snapshot->name]);
});

CreatingSnapshot / LoadingSnapshot are also useful places to abort (throw) if, say, the target env is production.

CI / test integration. The classic pattern is to check a small snapshot into the repo (or pull it in CI) and load it in a test bootstrap or a Pest beforeAll, replacing slow factory seeding for integration suites. Use --drop-tables=0 when loading into a DB where you want to preserve schema and only insert data — useful when the target DB is a shared test instance and dropping tables would break other suites.

Extra dumper flags via the connection config. Postgres restores commonly need ownership/privilege adjustments:

'pgsql' => [
    // ...
    'dump' => [
        'addExtraOption' => '--no-owner',
    ],
],

Gotchas and Tips

  • The snapshots disk must exist before any command runs. This is the #1 first-run failure. If you renamed the disk, also update db-snapshots.disk.
  • snapshot:load drops all tables by default. That's destructive on the target connection. Guard scripts, and use --drop-tables=0 when you only want data merged in.
  • Memory blowups on large files. Without --stream, the whole dump is read into memory. If a load dies with an OOM, --stream is the fix — it was hardened in 2.9.0 for chunk-boundary and continued-line cases, so stay on a recent 2.x.
  • The DB client binaries must be installed and on PATH. mysqldump, pg_dump/psql, sqlite3. Version mismatches between client and server (especially pg_dump older than the server) produce confusing errors that look like package bugs.
  • MariaDB is supported, but it's routed through the MySQL dumper. Changelog 2.6.1 added explicit MariaDB support; older versions may misdetect driver.
  • Postgres meta-commands. psql \ commands in dumps were skipped starting 2.7.2 — if you're on an older version and see invalid command \... errors on load, upgrade rather than editing the dump.
  • Config caching. After changing db-snapshots.php or the connection dump array, run php artisan config:clear in local dev. In production, re-cache.
  • Temp directory permissions. storage/app/laravel-db-snapshots/temp must be writable; in containerized deploys storage is often a read-only or ephemeral mount.
  • Snapshot names are filenames. Auto-generated names contain spaces (2017-03-17 14:31). Quote them in shell scripts, or always pass explicit kebab-case names in automation.
  • --latest is lexical/sort-order based on names, not a hidden "newest" index. If you mix custom names with date names, "latest" can surprise you (e.g. zzz-test beats a timestamp). Prefer dated prefixes for automated snapshots.
  • --table + --exclude together silently ignores --exclude. Validate in your own wrapper scripts if this matters.
  • Loading a gzipped snapshot into a different connection has had fixes (2.5.2): confirm your version before assuming a decompression bug is yours.
  • This tool is not a production backup strategy. No encryption, no integrity checks, no incremental dumps, no verification step. Treat it as a developer/staging convenience; keep real backups on a purpose-built system.
  • Extension points are thin by design. Config + six events + dump.addExtraOption is essentially the whole API. If you need post-dump transforms (scrubbing PII, rewriting DEFINER clauses), listen to CreatedSnapshot and post-process the file on the disk — or wrap the artisan command in your own command.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
thuraaung2493/laravel-rulecraft
cyberwizard/schedule-catchup
livetennisapi/livetennisapi-laravel
roundly-consulting/notifications-for-laravel
flightsadmin/bootstrap-starter-kit
lasserafn/laravel-intempus
likyly/sdk
tdt/input
coreation/php-shapefile
coreation/gisconverter
primix/widgets
primix/notifications
primix/actions
primix/tables
primix/details
primix/forms
primix/support
marcelgwerder/laravel-api-handler
firebrikdotcom/conveyor-laravel-broadcaster
kanata-php/conveyor-laravel-broadcaster