Search by

sextanet / laravel-database-copy

sextanet

Copy databases between environments, anonymized before they leave the source

Package info

github.com/sextanet/laravel-database-copy

pkg:composer/sextanet/laravel-database-copy

Fund package maintenance!

SextaNet

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-10-05 01:37 UTC

This package is auto-updated.

Last update: 2026-10-05 01:41:23 UTC


README

Latest Version on Packagist GitHub Tests Action Status

Copy a database between environments (e.g. production → staging) through a disk such as S3. The copy is anonymized before it leaves the source server, so the real data never reaches the bucket nor the other environment.

Production ──database-copy:export──▶ dump → anonymization database (same server) → anonymize → dump → encrypt
                                                                                                   │
                                                          disk: {environment}/{name}/{Y-m-d-H-i-s}.zip
                                                                                                   │
Staging    ◀──database-copy:import── decrypt → check it is anonymized → replace database → migrate ┘

Installation

composer require sextanet/laravel-database-copy
php artisan vendor:publish --tag="database-copy-config"
DATABASE_COPY_DISK=s3
DATABASE_COPY_PASSWORD=          # the SAME in every environment
DATABASE_COPY_NAME=my-app        # folder of this app in the disk (default: slug of APP_NAME)

# Source environment only
DATABASE_COPY_ANONYMIZATION_DATABASE=   # default: {database}_anonymized
DATABASE_COPY_EMAIL_DOMAIN=anonymized.test
DATABASE_COPY_KEEP_EMAILS=seba@sextanet.cl   # rows that keep their data, comma separated

The source environment needs mysqldump/mysql (or sqlite3, pg_dump/psql) and an empty anonymization database on the same server that the database user can write to:

CREATE DATABASE my_app_anonymized;
GRANT ALL PRIVILEGES ON my_app_anonymized.* TO 'my_app'@'localhost';

It is emptied after every export, even when something fails. With SQLite there is nothing to create: the file (database/database_anonymized.sqlite by default) is created and deleted on every export.

Anonymization

config/database-copy.php is the source of truth of what is personal data. Add every table or column with personal data there:

'tables' => [
    'users' => [
        'name' => 'first_name',
        'last_name' => 'last_name',
        'rut' => 'rut',
        'email' => 'email',
        'phone' => 'phone',
        'birthday' => 'null',
        'password' => 'password',
        'remember_token' => 'null',
    ],
    'comments' => [
        'email' => 'email',
        'ip' => 'ip',
        'user_agent' => 'user_agent',
        'address' => 'address', // any Faker formatter
    ],
],

'truncate' => ['sessions', 'password_reset_tokens', 'personal_access_tokens', 'jobs', 'failed_jobs'],

Tables or columns that do not exist are skipped. Anonymized tables need an id column.

Usage

# Source (production): upload an anonymized copy
php artisan database-copy:export

# Target (staging, local): replace this database with the latest copy from production
php artisan database-copy:import
php artisan database-copy:import --from=staging
php artisan database-copy:import --file=production/my-app/2026-10-04-03-30-00.zip

Copies are named with the date of the source app in its timezone (config('app.timezone'), UTC by default).

Schedule the export in the source environment:

Schedule::command('database-copy:export')->dailyAt('03:30');

Safety:

  • database-copy:import never runs in protected_environments (production by default) and asks for confirmation (unless --force).
  • It refuses a copy that is not anonymized (database-copy:export --without-anonymization) unless --with-real-data.
  • The copy is decrypted and checked before the database is touched.
  • The export refuses to anonymize when the anonymization database is the source database.

Testing

composer test

Credits

License

The MIT License (MIT). Please see License File for more information.