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.
Architecture fit
.env file and the env()/config() boundary — but 2.2.0 widens that seam in two directions that matter. Additive surface grows substantially (env:diff, env:sync, env:unset, env:restore, --file, encrypted-file support, boot-time validation, six rule sets, two events). Additive command surface is low-risk; additive runtime surface is not.validate_on_boot (log or exception). That moves the package from a CLI developer tool into the web request path on every request. This is a category change, not a feature. It is defensible in log mode as a canary; exception mode in production makes an invalid env key a total outage rather than a startup failure — strictly worse than failing at boot.env() returns the new value." This narrows one divergence (file vs. env()) but does not fix the config-cache trap: once Laravel's config repository is populated, config() values are already materialized and a post-save env() mutation does not propagate to them. The most dangerous variant of the original trap survives..env is not loaded) or another file is targeted, values are read from the file itself" introduces environment-dependent read semantics: the same EnvClient::get() returns a different source depending on config-cache state and --file. Deterministic within a process, but a debugging hazard and a real source of "it behaved differently in staging" incidents.phpdotenv + Rule::in does not replicate in an afternoon. But imliam/laravel-env-set-command and georgehanson/laravel-env-editor now overlap more, not less, because this package has moved toward their feature set.Integration feasibility
composer require. 2.2.0 adds illuminate/encryption as a direct dependency — small, first-party, low risk, but it enlarges the installed footprint and means the encrypted-env path is now on our dependency graph whether or not we use it.env:get masks secrets by default. Any existing script, Makefile, or CI step that captures env:get output to consume a value will silently receive ********. It will not error — it will produce a wrong value. This is the highest-priority regression to hunt for, and it argues for pinning rather than floating.env:generate now prints masked values next to each variable. Anything parsing that output for key names needs a re-check.--reveal), config-cache handling (documented, though the answer is "behavior changes"), encrypted files (supported). Still unresolved: atomicity (temp file + rename) and locking are not claimed by the release notes. env:restore and the backup option are recovery, not atomicity — a torn write still happens, you just have a file to restore from. And the backup is a single <file>.backup, so a second bad write overwrites the last known-good copy.--file on all commands is powerful and expands blast radius: it makes it trivially easy to point write commands at a file outside the intended environment. Path handling and any containment/sandboxing is now an explicit review item.Technical risk
env:sync, env:unset, env:restore, --file, and encrypted writes all mutate artifacts the application cannot boot without. The category risk is unchanged; the number of commands that can trigger it roughly doubled.validate_on_boot = exception converts a misconfiguration into a fleet-wide 500 loop with no deploy to roll back. Even log mode adds per-request overhead and log volume. This should be treated as opt-in-for-canary-only, never a default.env() mutation does not update config(). Operators will still see stale framework behavior after a successful-looking write.env:get and env:generate, with --reveal as an explicit opt-in, is the right design. Residual risk: --reveal in CI logs, exception messages from InvalidEnvironmentException (does it interpolate values?), and the EnvironmentFileUpdated/EnvironmentVariablesGenerated event payloads — do the events carry values, and are they masked? That is an unaudited leak channel introduced by this release.--key/--cipher on a write is a destructive operation on a file whose plaintext you may not have. Test the round-trip, including failure and rollback..gitattributes exclusions — this answers the static-analysis and hygiene questions that were previously open. Still unknown: security disclosure process, test coverage figure, CI matrix breadth (Laravel/PHP versions actually exercised), and maintainer/bus factor.Key questions
.backup rotated, or is the previous good copy overwritten on each write?validate_on_boot do under exception — throw on every request, cache the result, or throttle? Does it run before or after config load, and does it mask values in InvalidEnvironmentException messages?EnvironmentFileUpdated / EnvironmentVariablesGenerated event payloads contain raw secret values, and are they masked?--file accept arbitrary paths (absolute, ../)? Is there containment, confirmation, or a protected-path guard?env(), what is the documented behavior for already-resolved config() values, and does the package recommend or automate config:clear?env:get's masking change documented as breaking, and is there a migration note for scripts?Stack fit
.env shapes. env:diff/env:sync against .env.example is a genuine, if modest, ergonomic win for onboarding and drift checks — the best-fit use case remains CI preflight and developer onboarding.validate_on_boot pulls against that fit. It invites production runtime use of a package with zero dependents. Keep the boundary explicit: validation belongs in a deploy preflight step, not in the request lifecycle. If validate_on_boot is used at all, log mode only, on one canary service.Migration path
env:get masking is a breaking change for consumers. Treat 2.2.0 as a minor-version-numbered breaking release and do a consumer audit before bumping.EnvReader/EnvValidator/EnvWriter behind our own thin interfaces, because the package's read semantics now vary by config-cache state and --file, and because EnvForgetterInterface (new) signals the vendor is refactoring its own contracts.env:sync and --file make that mistake easier to make than it was in 1.x — write the prohibition down.Compatibility
env:sync against a fixture .env.example, env:unset on a key with a quoted value, env:restore after a deliberate corruption, encrypted write/read/rewrite with the correct and an incorrect key, and --file against a path outside the project root.env:get for a secret-bearing key must now fail loudly (detect ***) rather than pass a masked string downstream. Verify event payloads are masked.Sequencing
--file path handling, event payload contents, and exception message masking.env:get masking consumer audit.env:get, env:diff) in onboarding docs for one team.env:set, env:unset, env:restore) in local/dev only, with mandatory backup and a post-write config:clear in the same scripted step.validate_on_boot off by default, log at most, exception prohibited outside local.Maintenance
.gitattributes discipline signal a maintainer who cares. That is a meaningful upgrade over 1.x and the strongest argument in this release.Support
Scaling
.env files are per-instance, so any write workflow conflicts with immutable infrastructure. env:sync does not change this; it accelerates it, which is worse if misapplied.validate_on_boot is the one feature that scales outward to every request, and that is precisely why it should be off. Per-request validation cost is small individually and organizational surprise is large.Failure modes
.env → boot failure. Backup/restore makes recovery possible, but a single .backup slot means a second bad write destroys the good copy. Recovery is not atomicity.$, #, spaces, quotes, newlines) → passes boot, fails later. env:sync now propagates such values across files automatically, amplifying impact.env:get post-2.2.0 receives ******** and stores it as a credential. Fails at the far end of the pipeline, hardest to trace.validate_on_boot = exception with an invalid key → every request 500s; no deploy to roll back; recoverable only by fixing config on the box.--file misfire → writes to the wrong file, potentially outside the project, potentially production.--key/--cipher → destroyed ciphertext, plaintext not recoverable from the artifact.--reveal in CI logs, or via event payloads / InvalidEnvironmentException messages.Ramp-up
--file risk, encrypted-file key handling, config-cache invalidation, and why validate_on_boot=exception is prohibited. That is a real onboarding tax for a tool with 16 stars and 0 dependents.validate_on_boot off or log-only, backup mandatory, and a hard rule against production secret management. The 2.2.0 quality signals and the encrypted-env and diff/sync features justify continuing the pilot — they do not justify standardizing. Re-evaluate on evidence of adoption beyond single-digit dependents, a published CI support matrix, a stated security disclosure process, and one clean quarter without a breaking change at the patch/minor level.How can I help you explore Laravel packages today?