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

Laravel Masked Db Dump Laravel Package

beyondcode/laravel-masked-db-dump

Create safe, shareable database dumps from your Laravel app. Mask sensitive columns like emails, names, and tokens with customizable replacements, so you can hand off realistic data to teammates or use it in local development without leaking production secrets.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install as a dev dependency. Never let this land in a production artifact.

composer require beyondcode/laravel-masked-db-dump --dev

Verify your build actually runs composer install --no-dev — a shared all-environment artifact will silently ship it.

2. Publish the config, then read the stub before you edit it.

php artisan vendor:publish --provider="BeyondCode\LaravelMaskedDump\LaravelMaskedDumpServiceProvider"

This gives you config/masked-db-dump.php — the entire public API surface of the package. There are no other knobs, no events, no plugin layer. Treat this file as the reviewable artifact it is.

3. Check the command signature. php artisan db:dump --help is the first thing to run; options for output path and gzip have shifted across majors and the README lags the tag more often than you'd like.

4. Start with one table, not your schema. A first useful case that pays for itself immediately:

// config/masked-db-dump.php
return [
    'exclude_tables' => ['migrations', 'sessions', 'jobs', 'failed_jobs', 'cache'],
    'tables' => [
        'users' => [
            'name'  => 'name',
            'email' => 'safeEmail',
        ],
    ],
];

Run the dump, then open the generated SQL file and grep for a real email you know exists in the DB. Do this before you configure a second table. The tool's safety model is "you mapped everything that matters," so your first job is calibrating what "everything" means on your schema.

Implementation Patterns

Defaults vs. per-table overrides. The config has a defaults block (rules applied everywhere) and a tables block (per-table rules). The high-leverage pattern is a small defaults set for the columns that appear on nearly every table — created_by, updated_by, email, phone — plus explicit tables entries only where the shape matters. Don't try to encode your full schema in defaults; that's how a name rule ends up clobbering tenant_name and breaking a slug.

Prefer PHP callables (5.0.0's documented style). A string value is a Faker property/method name; a closure gives you full control and is the only way to express anything non-trivial:

'users' => [
    'email' => fn () => fake()->unique()->safeEmail(),
    'phone' => fn () => fake()->numerify('+1##########'),
    'password' => fn () => bcrypt('password'),
],

Callables are what let you preserve formats (phone numbers that still parse), satisfy unique indexes (unique()), and produce deterministic output.

Determinism across tables is the pattern that saves you hours. If the same logical entity appears in two tables — users.email and orders.customer_email — one shared callable, defined once and referenced from both, or joins break in every downstream environment and present as an application bug:

$email = fn () => fake()->unique()->safeEmail();

return [
    'tables' => [
        'users'            => ['email' => $email],
        'orders'           => ['customer_email' => $email],
        'invitations'      => ['invitee_email' => $email],
    ],
];

(If you need stable values across separate runs, use a hash of the original value — fn ($value) => sha1($value . config('app.key')) — rather than random Faker. Deterministic-across-runs is the stronger property; it makes a masked dump a legitimate regression fixture.)

Never mask primary or foreign keys. Masking users.id or orders.user_id doesn't anonymise anything; it just destroys referential integrity. The only exception is a value used as a join key that must also be hidden (e.g. an email used for login) — and that's the deterministic-callable case above.

Exclude aggressively. Large, PII-bearing, and boring is the profile of a table that should never be in a dev dump: sessions, jobs, failed_jobs, cache, telescope_entries, personal_access_tokens, audit/log tables, password_resets. This is dual-purpose — it removes the most likely leak path and it cuts dump size and run time dramatically. In 5.0.0 exclude_tables takes an array; if you're upgrading from 4.x, re-verify this shape, because a stale single-string entry is not honoured and you'll silently dump sessions with real data.

Wire it into CI for fixtures. The same command produces a masked fixture database for integration tests — real cardinality, real enum distributions, real NULL rates, instead of three factories. Cache the artifact or regenerate on schema change; tie it to a measurable outcome (escaped-defect rate) or it won't survive prioritisation.

Wrap the command for anything repeatable. Since there's no event layer, the extension point is a thin Artisan command of your own that calls db:dump, then asserts on the output (tail of file, row counts, canary grep), gzips it, and uploads it wherever your environment provisioning expects. That wrapper is where your compensating controls live.

Keep the config under code review. The rule that makes this safe in practice: new PII column ⇒ new masking entry, enforced in the same PR as the migration.

Gotchas and Tips

Masking is fail-open. This is the defining risk. Unmapped tables and columns pass through verbatim — no strict mode, no allowlist enforcement, no "every *_ssn column must be mapped" assertion. There is no substitute for building your own post-dump check: grep the generated file for a canary set of known real values and fail the run if any hit. Audit the artifact, not the config diff.

Closures in config break php artisan config:cache. Laravel cannot serialise Closures. Worse, where config:cache is in play the failure mode can degrade toward unmasked output rather than a hard error. Run php artisan config:clear before dumping, assert it in CI, and treat any environment that runs config:cache as a leak vector until proven otherwise.

Faker output violates real constraints and kills the dump mid-INSERT. enum/CHECK constraints, VARCHAR limits, and unique indexes are all live hazards. fake()->text() on a VARCHAR(50) or a state enum column will truncate the dump — and a truncated file still looks like a complete one. Validate the tail of the file and the row counts, not just the exit code. Pick generators that match the column's domain, not just its semantics.

mysqldump/pg_dump version mismatches surface as opaque exceptions. The package shells out to your DB client binary; pin it in CI images and know which version your local machine has.

Masking is column-value substitution, not a data-governance engine. No audit log of what was masked, no JSON/binary column handling, no per-environment mask strength, no plugin layer. If you need any of that, you're post-processing the dump or wrapping the command — plan for it rather than discovering it.

Gitignore the output. A masked dump in a repo is a permanent record of what you thought was safe two months ago.

Treat major upgrades as tracked tickets, not Dependabot merges. 5.0.0 changed the exclusion config shape and shifted the preferred masking style to callables. Either change on its own can convert a working workflow into a silent PII leak. Re-run your canary grep and manually inspect a dump's INSERTs after every major.

Small-maintainer, zero-dependents, dev-only. Bounded blast radius — an abandonment costs you a custom Artisan command, not an outage — but you are your own QA. Don't pitch this as compliance tooling; it's a developer hygiene tool that removes the "someone posts a dump in Slack" path. Position it as risk reduction, not risk elimination.

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.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core