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

Envclient Laravel Package

lionix/envclient

Laravel package for working with .env files programmatically: read, update, and manage environment variables from your app or an admin panel, so configuration changes can be made without manual file editing or redeploys.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package with Composer:

composer require lionix/envclient

Laravel’s package discovery should register the service provider automatically. On older Laravel versions, add the provider manually in config/app.php. Publish the package config so you can see what it controls:

php artisan vendor:publish --provider="Lionix\EnvClient\EnvClientServiceProvider"

Start by opening the published config (the 2.2.0 notes reference config/env.php, including the hidden patterns used for secret masking) and the package README. The config controls the .env file location, secret masking, the backup option, and validate_on_boot behaviour. Then discover the exact command signatures — this release added several:

php artisan list | grep -i env

As of 2.2.0 the command surface is roughly env:get, env:set, env:unset, env:list, env:diff, env:sync, env:restore, env:generate, all accepting a --file option (plus --encrypted, --key, --cipher for encrypted files). Confirm the exact flags from php artisan list before scripting them.

The best first use case is now a drift check plus a deployment guard. Wire env:diff into CI so a feature branch that adds a config key fails until .env.example is updated, then validate before caching:

php artisan env:diff            # non-zero exit if env file and .env.example disagree
php artisan env:get APP_KEY --reveal > /dev/null
php artisan config:cache

That combination catches the two most common production failures: an undocumented new variable and a missing or malformed value that only surfaces when the app boots.

Implementation Patterns

Use the fluent client behind a small application service. Rather than sprinkling the package facade through controllers, wrap it — including the new forget():

namespace App\Support;

use Lionix\EnvClient\Facades\EnvClient;

class Environment
{
    public function get(string $key, mixed $default = null): mixed
    {
        return EnvClient::get($key, $default);
    }

    public function set(string $key, string $value): void
    {
        EnvClient::set($key, $value);
    }

    public function forget(string $key): void
    {
        EnvClient::forget($key); // EnvForgetterInterface, implemented by EnvSetter
    }

    public function has(string $key): bool
    {
        return EnvClient::has($key);
    }
}

This isolates the package API, makes testing easier, and gives you one place to add logging, key allow-lists, or backup handling.

Keep env:diff in CI and env:sync in provisioning. They solve different problems. env:diff is a read-only gate:

- run: php artisan env:diff

env:sync writes missing keys from .env.example into the target file, which is useful when standing up a fresh environment — but it writes placeholder values, so treat it as a scaffolding step, not a repair step for a live production .env. Review its semantics on a throwaway file first.

Turn on backup before any scripted writes. The backup option copies the file to <file>.backup before every change, and env:restore puts it back. Enable it in config for any environment where you script env:set/env:unset:

# .env or .env.<environment>
ENVCLIENT_BACKUP=true

Combined with the "no rewrite when nothing changes" behaviour, this makes bulk provisioning idempotent and recoverable.

Use --file for multi-file workflows instead of editing .env. Instead of swapping files in and out of the project root, target them explicitly:

php artisan env:set DB_HOST="$DB_HOST" --file=.env.staging
php artisan env:diff --file=.env.staging

This also covers the case where the config is cached and .env isn’t loaded — with --file, values are read from the file itself rather than the runtime environment.

Keep encrypted files in the repo, not the plaintext. With --encrypted, --key and --cipher you can read and update a file produced by Laravel’s env:encrypt without writing decrypted contents next to the application:

php artisan env:get APP_KEY --file=.env.production.encrypted --encrypted --reveal
php artisan env:set CACHE_STORE=redis --file=.env.production.encrypted --encrypted

Supply the key from your CI secret store (or LARAVEL_ENV_ENCRYPTION_KEY), never from a committed file. Note illuminate/encryption is now a direct dependency, so it will be present, but the key handling is still your responsibility.

Use validate_on_boot deliberately. The new option (log or exception) validates the environment on every web request and throws InvalidEnvironmentException. exception is a reasonable default for staging; in production, prefer a startup check plus log, and register a handler so the exception degrades gracefully:

// bootstrap/app.php (Laravel 11+) or app/Exceptions/Handler.php
->withExceptions(function (Exceptions $exceptions) {
    $exceptions->render(function (InvalidEnvironmentException $e) {
        report($e);
        return response('Service misconfigured', 503);
    });
})

Compose the ready-made rule sets. AppRules, DatabaseRules, MailRules, QueueRules, RedisRules and AwsRules cover the standard keys; use them in a scheduled health command and layer your own application-specific keys on top:

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Validator;

class ValidateEnvironment extends Command
{
    protected $signature = 'app:validate-env';

    public function handle(): int
    {
        $validator = Validator::make($this->currentEnv(), [
            ...DatabaseRules::rules(),
            ...MailRules::rules(),
            'FEATURE_FLAG_X' => ['required', 'boolean'],
        ]);

        if ($validator->fails()) {
            foreach ($validator->errors()->all() as $error) {
                $this->error($error); // key names and status only — never values
            }

            return self::FAILURE;
        }

        return self::SUCCESS;
    }
}

Read the file directly (via the client or --file) rather than config(), otherwise a cached production environment validates the cached values, not the current .env.

Subscribe to EnvironmentFileUpdated and EnvironmentVariablesGenerated for audit trails. These are the natural hook for "who changed what, when" — log key names only, and ship them to your audit channel rather than the application log:

Event::listen(EnvironmentFileUpdated::class, function ($event) {
    AuditLog::record('env.updated', ['keys' => $event->keys /* names only */]);
});

Test against a fixture file, and assert on masking. Point the package at a temporary env file via the --file option or config override in your test suite, and never let tests read or write the real project .env. Add a test that env:get output does not contain a hidden value and that --reveal does — that behaviour is now a security boundary.

Use it for diagnostics, not as a config source. The package reads and writes the env file; your application should still consume configuration through config(). Use the client to inspect and manage the file, and use Laravel config for runtime behaviour.

Gotchas and Tips

  • env:get now masks secrets by default — this is the breaking change in 2.2.0. Any script that pipes env:get into another tool must pass --reveal. Audit your deploy scripts before upgrading.
  • --reveal is a secret-exfiltration footgun. It prints plaintext to stdout, which lands in CI logs, terminal scrollback, and shell history. Use it only where you immediately consume the value, and never inside a set -x script.
  • Saving updates the runtime environment. After env:set, env() returns the new value for the rest of the request or command. config() does not — and with config:cache active, the change is invisible until you re-cache. Always write values before php artisan config:cache, or re-run it afterwards.
  • Runtime writes do not affect already-booted processes. Octane workers, queue workers, and long-running daemons cache environment state at boot. Restart them after changes.
  • validate_on_boot runs on every request. With exception it also means a bad .env takes the whole site down rather than one deploy step. Budget for the filesystem read, prefer validating once at boot/deploy, and treat per-request exception mode as a staging-only posture.
  • .backup files contain secrets. Add *.backup (and any --file variants) to .gitignore, keep the same restrictive permissions as .env, and prune them — env:restore only knows about the most recent one.
  • env:sync can overwrite or invent values. Confirm whether it fills only missing keys or replaces differing ones, and whether it writes example placeholders. Run it against a copy first; a silent placeholder is worse than a missing key.
  • Encrypted-file workflows hinge on key custody. --key on the command line leaks via process listings and shell history. Prefer an environment variable or CI secret injection, and confirm the --cipher matches whatever env:encrypt used.
  • Values are strings, and quoting matters. Spaces, #, =, quotes, $, and multiline values can break naive .env writers. Test round-trips with realistic secrets and connection strings before trusting bulk writes.
  • Comments and formatting may be lost. Programmatic writes can reorder keys or strip comments. Treat .env edits as structured data, and keep .env.example or a secret manager as the source of truth.
  • File permissions are the usual production failure. The process running artisan must own or be able to write the file. Prefer running writes as the deploy user, not the web server user — especially now that backups double the files that need correct ownership.
  • Concurrent writes can corrupt the file. Do not call write commands in parallel. Use deployment locks and avoid per-request writes entirely.
  • Validation rule semantics vary by set. Confirm whether a given rule checks key presence, value format, or both, and whether it reads from the file or from env(). The bundled rule sets are opinionated — review them against your own key names before adopting.
  • Do not log secret values. Artisan output, CI logs, and the event payloads can expose credentials. Print key names and validation status only; the package masks env:get/env:generate output, but your own listeners and error messages don’t get that for free.
  • Keep secrets out of images and version control. Inject env values at deploy time (or ship an encrypted file plus the key); use the package to manage the resulting file, not to store secrets in your repository.
  • Pin the version and review the source. The package still has low adoption and zero known dependents. It is MIT-licensed and small enough to audit, but pin an exact version, read the write and encryption logic, and cover critical paths with your own tests.
  • Back up before bulk changes. Even with the backup option, copy the file first or implement a write-to-temp-then-rename wrapper so a failed deployment cannot leave a truncated .env.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource