Pull database and storage files from remote Laravel environments to your local machine. Uses spatie/laravel-db-snapshots for database operations and rsync for file transfers.
- PHP 8.3+
- Laravel 11 or 12
- SSH access to remote host (key-based auth recommended)
rsyncinstalled locally and on remote- Remote server must have
spatie/laravel-db-snapshotsinstalled
This package relies on spatie/laravel-db-snapshots for database operations. You need to configure it on both local and remote environments.
Add a disk for storing snapshots in config/filesystems.php:
'disks' => [
'snapshots' => [
'driver' => 'local',
'root' => database_path('snapshots'),
],
],php artisan vendor:publish --provider="Spatie\DbSnapshots\DbSnapshotsServiceProvider"Important: The snapshot filesystem configuration must be identical on both local and remote environments. This package uses your local
db-snapshots.diskconfiguration to determine where snapshots are stored on the remote server. If the remote has a different snapshot path configured, pull operations will fail.
composer require jorisnoo/laravel-remote-syncPublish the config file:
php artisan vendor:publish --tag="remote-sync-config"Add your remote environments to config/remote-sync.php or use environment variables:
REMOTE_SYNC_PRODUCTION_HOST=forge@your-server
REMOTE_SYNC_PRODUCTION_PATH=/home/forge/your-app.com
REMOTE_SYNC_STAGING_HOST=forge@staging-server
REMOTE_SYNC_STAGING_PATH=/home/forge/staging.your-app.com
REMOTE_SYNC_DEFAULT=productionreturn [
'remotes' => [
'production' => [
'host' => env('REMOTE_SYNC_PRODUCTION_HOST'),
'path' => env('REMOTE_SYNC_PRODUCTION_PATH'),
],
],
'default' => env('REMOTE_SYNC_DEFAULT', 'production'),
// Storage paths to sync (relative to storage/)
'paths' => [
'app',
],
// Tables to exclude from database snapshots
'exclude_tables' => [
'cache',
'cache_locks',
'sessions',
],
// Timeouts in seconds
'timeouts' => [
'snapshot_create' => 300,
'snapshot_download' => 600,
'snapshot_cleanup' => 60,
'file_sync' => 1800,
],
];php artisan remote-sync:pullPrompts you to select a remote and what to pull (database, files, or both).
Options:
--no-backup- Skip creating a local backup before pulling--keep-snapshot- Keep the downloaded snapshot file after loading--full- Include all tables (ignoresexclude_tablesconfig) and drops all local tables before loading
php artisan remote-sync:pull-db productionOptions:
--no-backup- Skip creating a local backup before pulling--keep-snapshot- Keep the downloaded snapshot file after loading--full- Include all tables (ignoresexclude_tablesconfig) and drops all local tables before loading
php artisan remote-sync:pull-files productionOptions:
--path=app/uploads- Sync only a specific path--delete- Delete local files that don't exist on remote
Push local data to a remote (requires push_allowed: true in config):
php artisan remote-sync:push # Interactive
php artisan remote-sync:push-db # Database only
php artisan remote-sync:push-files # Files onlyRemove old database snapshots from local and/or remote storage:
php artisan remote-sync:cleanup-snapshotsOptions:
--local- Only cleanup local snapshots--remote- Only cleanup remote snapshots--keep=5- Number of most recent snapshots to keep (default: 5)--force- Skip confirmation prompt--dry-run- Show what would be deleted without actually deleting
Examples:
# Cleanup both local and remote (interactive)
php artisan remote-sync:cleanup-snapshots
# Cleanup only local, keep 3 most recent
php artisan remote-sync:cleanup-snapshots --local --keep=3
# Cleanup only remote production snapshots
php artisan remote-sync:cleanup-snapshots production --remote
# Preview what would be deleted
php artisan remote-sync:cleanup-snapshots --dry-run
# Automated cleanup (cron-friendly)
php artisan remote-sync:cleanup-snapshots production --force --keep=5The package automatically detects if your remote server uses atomic deployments (Envoyer, Laravel Deployer, etc.) by checking for a /current symlink. When detected, it uses the correct working path.
- If
/currentexists → uses{path}/currentas the working directory - If
/currentdoesn't exist → uses{path}directly
If your path already ends in /current, detection is skipped and atomic mode is assumed.
- Commands refuse to run in production environment
- Confirmation prompt before syncing
- Local database backup created before pulling (unless
--no-backup) - Graceful cleanup on interrupt (Ctrl+C)
composer testThe MIT License (MIT). Please see License File for more information.
Built with Claude Code.