PHPackages                             rouxtaccess/laravel-sync - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. rouxtaccess/laravel-sync

ActiveLibrary[Database &amp; ORM](/categories/database)

rouxtaccess/laravel-sync
========================

Pull production databases, files and S3 buckets down to your local Laravel environment.

v3.0.1(1mo ago)231↓66.7%MITPHPPHP ^8.2CI passing

Since Jul 17Pushed 1mo agoCompare

[ Source](https://github.com/RouxtAccess/laravel-sync)[ Packagist](https://packagist.org/packages/rouxtaccess/laravel-sync)[ Docs](https://github.com/rouxtaccess/laravel-sync)[ RSS](/packages/rouxtaccess-laravel-sync/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (20)Versions (5)Used By (0)

Laravel Sync
============

[](#laravel-sync)

[![Latest Version on Packagist](https://camo.githubusercontent.com/1651804db1d04fd49b02e3a645aaa4ac73d2dec5f31b35f7eff64a979c1667f6/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f726f7578746163636573732f6c61726176656c2d73796e632e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/rouxtaccess/laravel-sync)[![Tests](https://camo.githubusercontent.com/ae5accbad90b9a6a3dfa96b90ca329dc3a4179c258c38726cd8548835958fec8/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f726f7578746163636573732f6c61726176656c2d73796e632f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/rouxtaccess/laravel-sync/actions/workflows/run-tests.yml)[![Total Downloads](https://camo.githubusercontent.com/bed8a4d0a2d69fb7f62d23103739a77014870b151eb6fdc597c5b63eae0b3c5b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f726f7578746163636573732f6c61726176656c2d73796e632e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/rouxtaccess/laravel-sync)

Pull production databases, files and S3 buckets down to your local Laravel environment with one interactive command.

Sync is built around named **groups** of **jobs**. A job is one unit of work (a database, a folder of files, a bucket). You configure groups once, then run them with `php artisan rouxt:sync`. Everything is a small registered class, so you can add your own sync types, database engines and post-sync hooks without touching the package.

Why this exists
---------------

[](#why-this-exists)

Refreshing local data from production usually means a pile of one off bash scripts. This package turns that into a reusable, safe, interactive tool:

- Databases are dumped live over an SSH tunnel, so nothing extra needs to be installed on the production server.
- Every job reports live progress. An interactive terminal draws a progress bar (per table for databases, per file for S3, a percent for rsync). A non-interactive run (`--yes`) or piped output prints plain progress lines instead.
- Database syncs pull a dump to a file first, then import it, so you can pull once and re-import the same dump repeatedly while testing without hitting production again.
- Imports are always downward. A sync only ever creates a new local database named `_`, it never writes back upstream.
- MySQL, MariaDB, PostgreSQL and SQLite are supported out of the box.
- Files come down over rsync, and S3 buckets sync with the AWS CLI.
- A hard environment guard refuses to run anywhere except your allowed environments.

Requirements
------------

[](#requirements)

- PHP 8.2, 8.3, 8.4 or 8.5
- Laravel 12 or 13
- The relevant client binaries on your machine for the jobs you run: `ssh`, `rsync`, `mysqldump` / `mysql`, `pg_dump` / `psql`, `sqlite3`, and the `aws` CLI.

Installation
------------

[](#installation)

Install the package with Composer:

```
composer require rouxtaccess/laravel-sync --dev
```

Then publish the config and seed an example store:

```
php artisan rouxt:sync-install
```

This publishes `config/sync.php`, writes a `sync-jobs.example.json` reference file next to the store, and adds the real store (`sync-jobs.json`) plus the `sync-dumps/` directory to your `.gitignore`. The store holds plaintext credentials and the dumps hold plaintext production data, so neither may ever be committed.

Quick start
-----------

[](#quick-start)

Run the command and follow the prompts to build your first group:

```
php artisan rouxt:sync
```

You will pick a sync type, answer a few questions (SSH target, database name, and so on), and optionally choose which after-hooks to offer. The group is saved to `sync-jobs.json`. Next time, run a named group directly:

```
php artisan rouxt:sync production
```

Add `--yes` to run every job in a group without prompting (useful in scripts). Add `--force` to run in an environment that is not on the allow list.

Sync types
----------

[](#sync-types)

KeyWhat it doesTransfer`db-over-ssh`Dumps a remote database live and imports it locallySSH tunnel, then `mysqldump` / `pg_dump` piped into the local client`db-from-s3`Restores the newest `.sql.gz` dump from an S3 folder`aws s3 cp`, `gunzip`, then the local client`files-over-ssh`Copies a remote directory to a local path`rsync -az` over SSH`s3-sync`Mirrors a bucket to another bucket or a local path`aws s3 sync`Both database types work in two phases. First a **fetch** pulls the remote data to a plaintext dump file on disk (`mysqldump` / `pg_dump` over the tunnel for `db-over-ssh`, or `aws s3 cp` plus `gunzip` for `db-from-s3`), sized and advanced per remote table. Then a **load** imports that dump file into a fresh local database named `_`, pre-scanning the file for its per-table markers to size the bar and running any after-hooks.

Because the fetched dump is a file, an interactive `db-over-ssh` or `db-from-s3` run that finds a recent dump for the job asks whether to reuse it (skipping production) or pull a fresh one. This makes it cheap to pull once and import many times while testing. A non-interactive run (`--yes`) always pulls fresh.

The load imports into a fresh local database named `_`. If that name already exists, an interactive run offers to abort, replace, or import under a different name. A non-interactive run (`--yes`) leaves it untouched.

Database drivers
----------------

[](#database-drivers)

`mysql` (MySQL and MariaDB), `pgsql` (PostgreSQL) and `sqlite` are registered by default. Local client settings are read from your app's `config/database.connections.*`, so the tool talks to the same local database your app does.

SQLite is file based and has no network port, so it cannot be tunnelled. A `db-over-ssh` job rejects it with a hint to use a `files-over-ssh` job to copy the database file instead. SQLite works with `db-from-s3` (a dump is restored into a local `.sqlite` file).

After-hooks
-----------

[](#after-hooks)

Once a database job succeeds, hooks can run. They are offered up front (in the same step as conflict handling) and executed at the end.

KeyWhat it does`swap-env-database`Points `.env` `DB_DATABASE` at the freshly imported database`run-migrations`Runs outstanding migrations on the imported database`anonymize`Runs your configured anonymizers on the imported databaseAnonymizers are defined in `config/sync.php` under `anonymizers`. Anonymization is opt-in, so the list ships empty and the hook is only offered when it has entries. Each entry is either a raw SQL statement or the class name of an invokable action.

The package ships two ready-to-use, driver-portable examples (they scrub the `users` table one row at a time, so replacements stay unique, and they no-op when a table or column is absent):

```
use Rouxtaccess\Sync\Anonymizers\AnonymizeUserEmails;
use Rouxtaccess\Sync\Anonymizers\AnonymizeUserPhoneNumbers;

'anonymizers' => [
    AnonymizeUserEmails::class,        // users.email -> user{id}@example.test
    AnonymizeUserPhoneNumbers::class,  // users.phone_number, msisdn, phone, mobile, ...
    "UPDATE users SET password = '', remember_token = NULL",
    App\Sync\Anonymizers\ScrubPaymentTokens::class,
],
```

An invokable action receives the connection name. Copy `AnonymizeUserEmails` as a template for other tables, or write your own:

```
class ScrubPaymentTokens
{
    public function __invoke(string $connection): void
    {
        DB::connection($connection)->table('payment_methods')->update(['token' => null]);
    }
}
```

The store file
--------------

[](#the-store-file)

Groups live in `sync-jobs.json` (the path is configurable via `SYNC_STORE_PATH`). It is plain JSON, so any editor treats it as a normal data file. The wizard writes it for you, and `sync-jobs.example.json` shows the shape. A job has `name`, `type`, a `config` block of the type's own fields, and an optional `after` list of hook keys:

```
{
    "production": {
        "jobs": [
            {
                "name": "db",
                "type": "db-over-ssh",
                "config": {
                    "driver": "mysql",
                    "ssh": "forge@1.2.3.4",
                    "db_host": "127.0.0.1",
                    "db_port": 3306,
                    "db_name": "forge",
                    "db_user": "forge",
                    "db_pass": "secret",
                    "target_prefix": "myapp"
                },
                "after": ["swap-env-database", "run-migrations"]
            }
        ]
    }
}
```

Environment guard
-----------------

[](#environment-guard)

By default the command only runs in the `local`, `development` and `testing` environments. Anywhere else it refuses unless you pass `--force`. Adjust the list in `config/sync.php`:

```
'guard' => [
    'allowed_environments' => ['local', 'development', 'testing'],
],
```

Extending
---------

[](#extending)

Every moving part is a class registered in `config/sync.php`. Append your own to the relevant array.

Write a custom sync type by implementing `Rouxtaccess\Sync\Contracts\SyncType`, a database engine by implementing `Rouxtaccess\Sync\Contracts\DatabaseDriver`, or a post-sync hook by implementing `Rouxtaccess\Sync\Contracts\AfterHook`. Register the class:

```
'types' => [
    // ...defaults
    App\Sync\Types\RedisSyncType::class,
],
```

Documentation
-------------

[](#documentation)

Deeper docs live in [`docs/`](docs):

- [`docs/human/`](docs/human) is plain-language documentation for developers and operators (running a sync, configuration, extending, security).
- [`docs/claude/`](docs/claude) is terse, code-focused steering for AI working on the package (architecture with diagrams, extending, testing).

AI agents (Laravel Boost)
-------------------------

[](#ai-agents-laravel-boost)

This package ships [Laravel Boost](https://laravel.com/docs/boost) support for coding agents. If your app uses Boost, running `php artisan boost:install` picks both of these up:

- **Guidelines** (`resources/boost/guidelines/core.blade.php`) fold into your `AGENTS.md` / `CLAUDE.md`. They are deliberately short (loaded on every turn) and cover the command, the store file, the guard, and the safety rules.
- A **`laravel-sync` skill** (`resources/boost/skills/laravel-sync/SKILL.md`) loads on demand when an agent is configuring, running, or extending the package. It carries the deeper material: the store shape, the extension contracts, and testing patterns.

Both also tell an agent that when it lacks the SSH keys or AWS credentials to run a sync, it should ask you to run it rather than fake it.

Security
--------

[](#security)

The store file holds connection details in plaintext, including passwords. `rouxt:sync-install` adds it to `.gitignore`. Keep it out of version control, and prefer SSH keys and AWS profiles over inline passwords where you can.

Fetched database dumps under `sync-dumps/` hold plaintext production data. The dump file is not anonymized (MySQL DEFINER clauses are stripped, but the rows are real); anonymization runs on the imported database through the `anonymize` hook, not on the dump file. `rouxt:sync-install` gitignores the directory too. Treat these files like the store: keep them out of version control.

Testing
-------

[](#testing)

```
composer test
```

License
-------

[](#license)

The MIT License (MIT). Please see the [license file](LICENSE.md) for more information.

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance93

Actively maintained with recent releases

Popularity13

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 62.5% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~4 days

Total

4

Last Release

34d ago

Major Versions

v1.0.0 → v2.0.02026-07-17

v2.0.0 → v3.0.02026-07-20

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/44562492?v=4)[RouxtAccess](/maintainers/RouxtAccess)[@RouxtAccess](https://github.com/RouxtAccess)

---

Top Contributors

[![JohnRoux](https://avatars.githubusercontent.com/u/4610241?v=4)](https://github.com/JohnRoux "JohnRoux (5 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (3 commits)")

---

Tags

laraveldatabasedevelopmentsyncrouxtaccess

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/rouxtaccess-laravel-sync/health.svg)

```
[![Health](https://phpackages.com/badges/rouxtaccess-laravel-sync/health.svg)](https://phpackages.com/packages/rouxtaccess-laravel-sync)
```

###  Alternatives

[laravel/ai

The official AI SDK for Laravel.

1.1k6.4M362](/packages/laravel-ai)[laravel/boost

Laravel Boost accelerates AI-assisted development by providing the essential context and structure that AI needs to generate high-quality, Laravel-specific code.

3.6k31.1M894](/packages/laravel-boost)[spatie/laravel-backup

A Laravel package to backup your application

6.1k26.6M288](/packages/spatie-laravel-backup)[spatie/laravel-health

Monitor the health of a Laravel application

89313.5M196](/packages/spatie-laravel-health)[spatie/laravel-medialibrary

Associate files with Eloquent models

6.2k47.7M739](/packages/spatie-laravel-medialibrary)[laravel/sail

Docker files for running a basic Laravel application.

1.9k220.0M1.5k](/packages/laravel-sail)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
