winter/laravel-config-writer
A Laravel package for writing and updating configuration files at runtime. It lets you modify config values programmatically and save them back to disk, making dynamic settings changes easier without manual file edits.
Architecture fit. winter/laravel-config-writer is a single-purpose utility library, not a framework extension. It sits at the file-system boundary of a Laravel app: it reads and rewrites PHP config arrays and .env key/value pairs. That is a deliberately narrow architectural role, and it fits only if we accept the underlying premise — that configuration is mutable state on disk at runtime, not an immutable deploy artifact. For an installer, setup wizard, or provisioning command it is a natural fit. For a request-path feature ("let admins edit SMTP settings from the UI") it is a meaningful architectural commitment that trades git-tracked config for operational mutability. Provenance is a positive signal: the package comes from the Winter CMS org and is exercised by their setup/update flow, meaning it gets real-world use beyond its 16 stars and 0 dependents. Verify this by reading the source and their installer before we lean on it.
Integration feasibility. Low friction: Composer install, MIT license, auto-discovered service provider, no schema or infrastructure change required. The API surface appears small enough to wrap behind our own interface in an afternoon. The real integration cost is not installation but the surrounding hardening we must add ourselves — atomic writes, permission handling, config-cache invalidation, and audit logging are almost certainly not provided at the level we need.
Technical risk. The dominant risks are correctness of file mutation and the operational assumptions it bakes in:
.env files while preserving comments, key order, quoting, escaping, and nested structures is where these libraries break. Expect edge cases with values containing #, spaces, quotes, or multi-line content.true becoming "1", null becoming "", integers becoming strings — subtle and easy to ship silently. This risk is now confirmed rather than theoretical: v1.2.2 (PR #13, "Added support for doubles") is a bug fix for float handling, meaning every release up to and including v1.2.1 mishandled a basic scalar type. Treat the type matrix as partially proven, not proven.config:cache is active or OPcache holds the old file. This is the most likely "it worked locally" failure.What changed in v1.2.2. One-line changelog, one PR, no breaking changes, no deprecations, no API surface change — floats are now written correctly. Materiality is low as a code change but non-zero as a signal: it confirms the type-coercion failure mode we flagged, it demonstrates the maintainer still patches correctness bugs (not just dependency bumps), and it raises the floor for anyone pinning versions. Net effect on the overall read: unchanged verdict, slightly better maintenance signal, slightly worse confidence in untested types.
Key questions.
nikic/php-parser) or regex/var_export? This determines whether comments and formatting survive.file_put_contents?DateTimeInterface, nested arrays with numeric keys, empty arrays, very large integers, INF/NAN? Is there a test suite covering round-trips, and can we read it?precision/serialize_precision ini settings or locale, and could that silently truncate or expand a value (e.g. 0.1 + 0.2)?config:cache / OPcache, or is that left entirely to the caller?Stack fit. Assumes a standard Laravel + Composer stack with writable config/ and a .env on disk. It is not a fit for immutable-image or serverless deployments unless we restrict it to build-time/CI use. Classify it as a setup-time dependency, not a runtime one, and place it in require-dev or in a Setup/Installer command namespace so it cannot be invoked from HTTP handlers by accident.
Migration path. Purely additive — no data model change, no schema migration, no user-facing behavior change on day one. Pin ^1.2.2 or later so we inherit the float fix. The safe sequence:
.env, then round-trip the file through git diff to see exactly what formatting churn it introduces. Extend this into a type round-trip matrix — write and read back true, false, null, 0, 1, -1, 0.5, 1e-7, a float with many decimals, a string containing #, spaces, quotes and newlines, an empty array, and a nested array — because v1.2.2's existence proves this matrix was not covered upstream.ConfigWriter interface of our own (set(string $key, mixed $value), delete(string $key)). Costs an hour, buys the ability to swap in a hand-rolled writer if the library disappoints — which matters given the 0-dependents signal.config:clear and, where applicable, OPcache invalidation inside the wrapper, not at call sites.chmod 600 on .env, backup of the prior file, and structured audit logging (key names only, never values).Compatibility. Check three things before committing: Laravel/PHP version constraints in composer.json; whether it conflicts with any existing env-manipulation code (e.g. brotzka/dotenv-editor, josegonzalez/php-dotenv) — running two dotenv writers is a recipe for corruption; and whether our deployment pipeline treats config/ as source-controlled (if so, automated writes generate diff noise that will annoy everyone within a month). The v1.2.2 patch is drop-in from v1.2.1 — no code changes required on our side, but any existing float values written by an older pin should be re-written and spot-checked, since a previously coerced value may already be persisted in a config file.
Sequencing against other work. Do not couple this to a larger settings-feature epic. It is a small, independent enabler. Land it as an internal utility with no external surface, use it in one command, and let it prove itself before it appears in any user story.
Maintenance. Low, and marginally improved by this release. Small surface area, MIT, established org behind it, and a correctness patch shipping in December 2025 confirms it is not abandoned and that defects get fixed rather than accumulating. Pinning a minor version is cheap insurance. The flip side of a small surface is that gaps get patched by us, not upstream — and v1.2.2 is the countervailing evidence: at least some gaps do get patched upstream, on a single-maintainer cadence. Budget a few hours a quarter, plus a fork contingency if a formatting bug bites.
Support. No commercial backing or SLA. Issue triage is community-speed — a one-line changelog with a single PR is characteristic of the project's communication style, so expect to read source rather than release notes. Owner should be the platform/DevOps team, since the failure modes are operational (files, permissions, caches) rather than application-logic ones. Do not let a product feature team own it in isolation.
Scaling. Writes are rare and I/O-bound, so throughput is a non-issue. Horizontal scaling is the issue: config written to one pod's disk is invisible to the rest of the fleet. Rule: writes happen at deploy time or in a single-writer job, never on a horizontally-scaled request path. If the feature genuinely requires runtime reconfiguration across nodes, the correct answer is a database-backed settings table with a cache layer, and this package is the wrong tool.
Failure modes to instrument.
config:cache still serves stale values. Highest-likelihood, hardest-to-notice failure. Mitigate with automated cache clearing and a read-back assertion after every write.true → "1", empty string → null, floats wrong until v1.2.2; surfaces as baffling runtime behavior far from the cause. Assume other types still have edges and add the read-back assertion as the general defence rather than testing type-by-type forever.precision/serialize_precision ini settings could round-trip a value differently than the caller passed it. Relevant for rates, thresholds, and multipliers.config/ or .env; fails loudly in staging, silently swallowed in a try/catch in production.Ramp-up. Very low for a mid-level engineer — under a day to be productive, most of which is spent reading the source rather than documentation, which is likely README-level only and demonstrably does not enumerate supported value types (that information lives in the source and in the PR history). The conceptual model (mutate a PHP array file, mutate a dotenv file) is trivial. The learning curve that actually matters is on the operational side: the team must internalize that these writes are rare, privileged, CLI-only, and always followed by a cache clear. Write that as a one-page runbook and a code-review checklist rather than relying on tribal knowledge.
How can I help you explore Laravel packages today?