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 Environment Importer Laravel Package

van-ons/laravel-environment-importer

van-ons/laravel-environment-importer helps you import environment variables into Laravel from .env files or custom sources. Validate and merge values, streamline deployment, and keep configuration consistent across local, staging, and production environments. Easy to install and configure.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package as a dev dependency — it should never be part of a production build:

composer require van-ons/laravel-environment-importer --dev

Publish the config (the service provider registers a config/environment-importer.php merge, so check vendor/van-ons/laravel-environment-importer/config/ for the actual tag name if vendor:publish asks for one):

php artisan vendor:publish --provider="VanOns\LaravelEnvironmentImporter\LaravelEnvironmentImporterServiceProvider"

Then look at exactly three things, in this order:

  1. config/environment-importer.php — this is the whole surface area of the package. Every key you need (environments, SSH credentials, backup_path, db_type, empty_tables, data_processors, database_processors, notification settings) lives here.
  2. src/Commands/ImportEnvironmentCommand.php — the single Artisan entry point, environment:import. Read handle() top to bottom; it is the workflow: tunnel → dump → import → file sync → processors → notification.
  3. src/Processors/ — the extension point. Processors\Data\* extends DataProcessor (row-level post-import), Processors\Database\* extends DatabaseProcessor (dump-level).

Your first use case is almost certainly "get staging's database onto my laptop without asking DevOps":

// config/environment-importer.php
return [
    'environments' => [
        'staging' => [
            'ssh_host' => env('IMPORT_SSH_HOST'),
            'db_type'  => 'mysql',
            'paths'    => ['storage/app/public', 'public/uploads'],
        ],
    ],
    'backup_path' => storage_path('imports'),
];

Then:

php artisan environment:import staging

Add the credentials to .env (not to the config file), ignore storage/imports in git, and you have a repeatable one-liner. Treat the first successful run as the real documentation — the published config is the only authoritative reference for key names.

Implementation Patterns

One environment block per source. Model each remote you might pull from (staging, production-readonly, review-123) as an entry under environments, and let the command's environment argument select it. Keep the per-environment SSH host and DB type inside the block so a single config file covers all of them.

Anonymize on the way in, not after. This is the reason to use the package over a raw mysqldump | mysql pipe. Register data processors in data_processors using the two supported syntaxes:

'data_processors' => [
    // no options
    \App\Import\Processors\ClearSessions::class,

    // with options
    AnonymizeUsers::class => [
        'model'  => \App\Models\User::class,
        'fields' => ['email', 'phone', 'name'],
    ],
],

Any custom processor implements applies(): bool and process(): void. Use applies() as the guard, not as a comment — it should return false when the target table is empty or when the relevant config is missing, so a half-configured processor degrades to a no-op instead of throwing mid-import.

Empty the noisy tables. Anything that is pure runtime noise — sessions, jobs, failed_jobs, telescope entries, cache — should be wiped rather than copied. The package exposes this via empty_tables; note the legacy alias:

// Backwards compatibility: 'sensitive_tables' was renamed to 'empty_tables'

If you inherit an older config, both keys still work, but write new configs against empty_tables.

Wrap it in a composer script so nobody has to remember the argument:

"scripts": {
    "import:staging": "php artisan environment:import staging --no-interaction"
}

--no-interaction matters: the command uses Laravel Prompts (select() for environment/SSH auth choices), and prompts block CI or scripted runs.

Chain local post-processing after the import. The package handles transport; your app's own resets belong in a follow-up script, e.g. php artisan migrate --force && php artisan db:seed --class=LocalDemoSeeder. Don't try to encode that into a processor — processors are row/dump scoped, not command scoped.

Notifications are a convenience, not a monitoring system. Failure notifications (mail/Slack) are useful when an import runs unattended on a scheduled box, but for a dev-machine tool the console output is the primary signal. Keep them configured to a channel you actually read, or leave them off.

Extension via config, not via forking. If you need behaviour the package doesn't ship, write a processor. Both processor types are plain classes resolved through the container, so you can constructor-inject your own services (anonymizers, fakers, redactors) rather than calling facades.

Gotchas and Tips

  • It will not work without SSH access to the source. The tunnel is established before the dump; if isDbTunnelReady() never returns true you get a failure that looks like a DB problem but is an SSH/auth/port problem. Test the raw ssh command first, outside the package.

  • backup_path must exist and be writable. The command creates directories recursively where it can, but a path outside the project (or on a read-only mount) fails late, after the dump. Prefer storage_path('imports') and add it to .gitignore.

  • rsync is assumed to be on the machine for file sync. macOS ships an ancient rsync at /usr/bin/rsync; if flags like --info=progress2 are used internally, install a modern one via Homebrew and make sure it wins on PATH. Also watch trailing slashes on path pairs — the classic rsync footgun.

  • DB engine is sniffed, not always declared. The command uses match (true) over helper checks (dbUsesMariaDb(), dbUsesMongo(), defaulting to MySQL). If you run a MariaDB/MySQL hybrid or an unusual version string, be explicit with db_type rather than relying on detection.

  • Import order is fixed and processors run last. Data processors operate on the already-imported database. If a processor depends on another having run, the config array order is your only ordering lever — document it in a comment next to the processors.

  • Never let this reach production. There is no built-in "am I in production" interlock documented; add your own guard if there is any chance the config ships:

    abort_if(app()->isProduction(), 403, 'Environment import is disabled in production.');
    
  • Debug with verbosity, and read the prefixes. Output is intentionally prefixed [DB] and [Files], so php artisan environment:import staging -vvv tells you which subsystem stalled. The top-level handle() has a single try/catch that prints $e->getMessage() — check the underlying ImportEnvironmentException message for the real config key that's missing.

  • Config access inside the package is indirect. Use getConfigValue() / getEnvironmentConfigValue() (both Arr::get-backed, dot-notation aware) if you contribute code back; calling config() directly bypasses the environment scoping and will read the wrong layer for per-environment keys.

  • Requirements are PHP ^8.2 and Laravel >=11. On older apps you'll get a confusing install resolution rather than a clear error — confirm your platform before blaming the config.

  • There is no test suite. You are the QA. Before trusting a new processor in a shared config, run the import once, then assert on the data manually (User::whereNotNull('email')->doesntExist() etc.). Keep a small smoke script in the repo instead of relying on package tests.

  • Contribute with the project's tooling. composer format then composer analyse (PHPStan level 5, no baseline, paths config/ and src/) — any patch that adds a new config key must also update the published config, or the accessor will silently return the default.

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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin