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

Db Snapshot Sync Laravel Laravel Package

phattarachai/db-snapshot-sync-laravel

A Laravel package for capturing database snapshots and syncing them across environments. It simplifies backing up, transferring, and restoring database state during development, testing, and deployment, with Artisan commands and configurable connections.

View on GitHub
Deep Wiki
Context7

Getting Started

phattarachai/db-snapshot-sync-laravel gives you a single artisan command, snapshot:sync, for moving database snapshots between environments — the classic use case being "refresh my local database from a known-good snapshot without hand-rolling mysqldump + scp + import every time."

Install and publish the config first, then read the published sync block before running anything:

composer require phattarachai/db-snapshot-sync-laravel
php artisan vendor:publish   # select the package provider

As of v1.4.0 the shipped default is a deny list, not an allow list:

'sync' => [
    'denied_environments' => ['production'], // env: DB_SNAPSHOT_SYNC_DENIED_ENVIRONMENTS
    'allowed_environments' => [],            // env: DB_SNAPSHOT_SYNC_ALLOWED_ENVIRONMENTS
],

That means the command is runnable in local, development, staging, testing, and anything else you name — everything except production. Your first run should be a deliberate one in local after you've confirmed APP_ENV is what you think it is:

php artisan snapshot:sync

The first real use case worth wiring up is the onboarding path: a new developer clones the repo, runs migrate, then snapshot:sync to get representative data instead of seeding ten rows of fixtures.

Implementation Patterns

Pick one gating strategy and stick to it. The precedence rule is the whole design of this feature: if allowed_environments is non-empty it decides alone — denied_environments is not consulted at all. So you have two mutually exclusive models:

  • Deny list (default): "run everywhere except these." Good for a team with ephemeral review apps and CI environments that are hard to enumerate.
  • Allow list: "run only here." Good for regulated or shared-cluster setups where a typo in APP_ENV shouldn't be survivable.

Don't half-migrate — a config with allowed => ['local'] and denied => ['production', 'staging'] reads like both are enforced, but only the allow list is.

Drive it from environment, not committed config. In config/db-snapshot-sync.php leave the arrays reading from env, then set the variables per environment in your .env, deploy secrets, or CI variables. That keeps the committed config diff-free across environments and lets a single developer override locally without touching tracked files.

Wrap it in a composer script or Makefile target so the sequence is explicit rather than tribal knowledge:

"scripts": {
    "db:refresh": [
        "@php artisan migrate:fresh --no-interaction",
        "@php artisan snapshot:sync"
    ]
}

Whatever snapshot:sync does to the target schema, ordering it against migrate:fresh is the difference between a clean local DB and a confusing half-migrated one. Verify which direction the package expects before encoding it in a script.

Treat it as a dev-environment primitive in CI. The v1.4.0 change makes this the natural pattern: a preview/review-app environment no longer has to be added to an allow list by name — it just runs, because it isn't production. Reserve the env vars for the environments you actually want to block.

Keep secrets out of the sync path. Anything you use to reach the source database belongs in .env/secret storage, never in the published config file — that file is committed and PR-diffable.

Gotchas and Tips

The upgrade footgun is the headline risk in v1.4.0. If you published config under 1.3 or earlier, it hard-codes 'allowed_environments' => ['local', 'development']. That non-empty array still wins, so you will not observe the new behaviour at all — snapshot:sync keeps refusing to run in staging and you'll assume the release is broken. After upgrading, diff your published config against the package's and replace the sync block wholesale rather than editing around it.

Default-open is a real behaviour change. Pre-1.4 defaulted to running in local/development; 1.4 defaults to running everywhere except production. Any environment name that isn't literally production in your denied list is now permitted. If you have prod, live, production-eu, a blue/green production slot, or a staging box pointed at production data, add them explicitly:

DB_SNAPSHOT_SYNC_DENIED_ENVIRONMENTS=production,prod,live,staging,production-eu

This is exactly the kind of change that deserves a grep across your .env, CI config, and deploy manifests rather than a config-cache-clear-and-hope.

APP_ENV is the gate, so it is also the failure mode. Anywhere the environment name is derived (queue workers, scheduled tasks, container entrypoints, phpunit.xml), the value may differ from what you assume. Confirm with php artisan env or app()->environment() in tinker on the box in question before trusting a green or red result.

Config caching will make you doubt your own memory. After changing any of the env vars, run php artisan config:clear (or config:cache in deploy pipelines). A stale bootstrap/cache/config.php silently serves the old arrays, and the symptom — "it still runs in staging, I definitely changed the variable" — looks identical to a precedence bug.

Check the env var list format before trusting it. These are array-valued settings fed from a single string; confirm the expected separator in the package's config comments and test it once with a deliberately wrong value. A malformed value that parses to a single junk environment name will fail open, not closed.

Empty is not the same as unset. allowed_environments being empty (or an env var resolving to an empty string/array) is what hands control back to the deny list. If you're programmatically building this config — a service provider, a multi-tenant bootstrap, a test — an accidental empty array silently switches gating modes. Assert on the resolved config in a test if you're doing anything dynamic.

Extension point worth knowing: because gating is pure config resolution, you can override it per-context (per-test-suite, per-tenant, per-CI-job) without forking the package — set the config at runtime in a service provider or phpunit.xml <env> block. Use this to hard-disable the command in any test suite that touches a shared database, so a stray snapshot:sync in a test can never point at something real.

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.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels