A Laravel package that adds a db:refresh-from-prod Artisan command, which replaces the local database with a copy of the production database. Production can be reached over SSH (a server you can log into) or directly on a Laravel Cloud MySQL database's public endpoint. Both MySQL and SQLite local connections are supported; the command picks the strategy from the local connection's driver and the configured source.
- Dumps the current local database to
storage/backups/as a safety net. - Opens an SSH tunnel to the production server.
- Dumps the production database through the tunnel, streaming to disk with a progress bar.
- Drops and recreates the local database (honoring the connection's charset and collation).
- Imports the production dump, streamed with a progress bar.
Same as above, minus the tunnel: mysqldump connects straight to the database's public endpoint over TLS. The dump runs with --single-transaction (consistent, no locking) and --no-tablespaces (Laravel Cloud database users are not granted the PROCESS privilege that mysqldump otherwise requires).
You must enable the cluster's public endpoint before syncing — "Org > Resources > Databases > ... > Edit settings > Enable public endpoint" — and you can disable it again afterwards. Credentials come from "View credentials" on the same menu.
- Snapshots the current local database file to
storage/backups/as a safety net (viasqlite3 .backup, which is WAL-safe). - Takes a consistent snapshot of the production database file on the server with
sqlite3 .backup. - Downloads the snapshot over
scpand removes the remote temp file. - Swaps the snapshot in as the local database file, clearing any stale
-wal/-shmsidecars.
The command refuses to run unless APP_ENV=local.
- PHP 8.2+
- Laravel 10, 11, or 12
- For MySQL:
mysqlandmysqldumplocally; for SQLite:sqlite3locally and on the production server - For the
sshsource:sshon your PATH (pluslsoffor the MySQL tunnel,scpfor SQLite) and SSH access to the production server (key-based auth recommended) - For the
cloudsource: a Laravel Cloud MySQL database with its public endpoint enabled, and amysqldumpthat understands--ssl-mode(Oracle MySQL 5.7+; see the SSL note below for MariaDB)
composer require abigah/db-sync-from-prod --devOptionally publish the config:
php artisan vendor:publish --tag=db-sync-from-prod-configDB_SYNC_SOURCE selects how production is reached: ssh (default) or cloud. The rest of the variables depend on that choice and on whether your local connection is MySQL or SQLite.
SSH settings are shared by both drivers.
DB_SYNC_SOURCE=ssh
# Shared
PROD_SSH_HOST=prod.example.com
PROD_SSH_USER=deploy
PROD_SSH_PORT=22
# MySQL
PROD_DB_HOST=127.0.0.1
PROD_DB_PORT=3306
PROD_DB_USERNAME=app
PROD_DB_PASSWORD=secret
PROD_DB_DATABASE=app_production
# SQLite
PROD_DB_PATH=/var/www/app/current/database/database.sqliteTake these from "View credentials" in the Laravel Cloud dashboard. Note that PROD_DB_HOST here is the public endpoint you connect to directly, not a host as seen from a production server.
DB_SYNC_SOURCE=cloud
PROD_DB_HOST=db-xxxxxxxx.ca-central-1.db.laravel.cloud
PROD_DB_PORT=3306
PROD_DB_USERNAME=xxxxxxxxxxxxxxxx
PROD_DB_PASSWORD=secret
PROD_DB_DATABASE=production| Variable | Source | Driver | Default | Description |
|---|---|---|---|---|
DB_SYNC_SOURCE |
— | both | ssh |
Where production lives: ssh or cloud. |
PROD_SSH_HOST |
ssh | both | — | SSH host of the production server. |
PROD_SSH_USER |
ssh | both | — | SSH user on the production server. |
PROD_SSH_PORT |
ssh | both | 22 |
SSH port. |
PROD_DB_HOST |
both | mysql | 127.0.0.1 (ssh only) |
DB host: as seen from the production server (ssh), or the public endpoint (cloud). |
PROD_DB_PORT |
both | mysql | 3306 |
DB port. |
PROD_DB_USERNAME |
both | mysql | root (ssh only) |
DB username on production. |
PROD_DB_PASSWORD |
both | mysql | `` (empty) | DB password on production. |
PROD_DB_DATABASE |
both | mysql | — | Name of the production database. |
PROD_DB_SSL_MODE |
cloud | mysql | REQUIRED |
--ssl-mode passed to mysqldump. Leave empty to omit it. |
PROD_DB_SSL_CA |
cloud | mysql | — | CA bundle to verify the server certificate against. |
PROD_DB_PATH |
ssh | sqlite | — | Absolute path to the production SQLite file on the server. |
DB_SYNC_LOCAL_CONNECTION |
both | both | config('database.default') |
Local connection (from config/database.php) to replace. |
DB_SYNC_BACKUP_DIR |
both | both | storage/backups |
Where local and production dumps are written. |
The cloud source requires a MySQL local connection; Laravel Cloud does not host SQLite databases.
Laravel Cloud requires TLS, so the dump runs with --ssl-mode=REQUIRED by default: the connection is encrypted, but the certificate is not verified. To verify it, point PROD_DB_SSL_CA at a CA bundle (/etc/ssl/certs/ca-certificates.crt on Linux, $(brew --prefix)/etc/ca-certificates/cert.pem on macOS). Avoid VERIFY_IDENTITY — the endpoint hostname does not match the certificate.
MariaDB's mysqldump does not understand --ssl-mode. If you're using it, set PROD_DB_SSL_MODE= (empty) to drop the flag; the client negotiates TLS on its own.
The backup directory is created on first run and seeded with a .gitignore that ignores its own contents, so dumps don't accidentally end up in version control.
php artisan db:refresh-from-prodYou will be shown which local database is about to be replaced and asked to confirm. The command aborts unless APP_ENV=local.
| Option | Description |
|---|---|
--source=ssh|cloud |
Override the configured source for this run. |
--dump=PATH |
Use an existing dump/snapshot file instead of pulling a fresh one (skips the production download). |
--skip-local-backup |
Skip backing up the local database before replacing it. |
The mysqldump progress bar is driven by an estimate from information_schema.tables (SUM(DATA_LENGTH + INDEX_LENGTH)), which reports on-disk storage, not dump size. The SQL dump is usually smaller than storage for InnoDB tables — indexes aren't dumped, and text compresses differently than on-disk pages. Expect the bar to finish before reaching 100% and then jump to done. The reported final byte count is exact.
If information_schema isn't reachable (e.g. the DB user lacks SELECT on it, or the connection times out), the estimate is skipped and the dump runs without a progress bar.
MIT