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

Dotenv Editor Laravel Package

pixelfed/dotenv-editor

A PHP package from PixelFed for editing .env files programmatically, letting you read, update, and manage environment variables from application code instead of handling the file manually.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a tiny wrapper around vlucas/phpdotenv's parser plus a line-buffer writer. It lets you read, mutate, and persist .env values from PHP. Treat it as ~300 lines of vendored code rather than a framework dependency — that framing determines how you should adopt it.

Install

composer require pixelfed/dotenv-editor

The pixelfed fork exists mainly to keep the original sven/laravel-dotenv-editor working on newer phpdotenv constraints. Before installing, open the fork's composer.json and confirm the illuminate/support and vlucas/phpdotenv ranges against your Laravel version. If they conflict, you're better off copying the source into app/Support/ and owning it — the surface area is small enough.

Registration

On Laravel 5.5+ package discovery should pick up the service provider. If not, add it to config/app.php:

'providers' => [
    Sven\DotenvEditor\DotenvEditorServiceProvider::class,
],
'aliases' => [
    'DotenvEditor' => Sven\DotenvEditor\Facades\DotenvEditor::class,
],

The fork kept the upstream namespace in most releases; confirm the FQCN by listing vendor/pixelfed/dotenv-editor/src before you write imports. That one check saves fifteen minutes of "class not found".

First use case

The canonical reason to install this is a first-run installer or an admin settings page that has to persist credentials the app can't already know. Start there:

DotenvEditor::load()
    ->setKey('DB_DATABASE', $request->database)
    ->setKey('DB_USERNAME', $request->username)
    ->setKey('DB_PASSWORD', $request->password)
    ->save();

Artisan::call('config:clear');

Read the source of DotenvEditor::class once, top to bottom, before you build on it. Note which methods return $this (chaining) and which return raw values — the API is not perfectly consistent across versions.

Implementation Patterns

The three-call contract

Almost every correct usage is load() → mutate → save(). load() parses the file into an in-memory buffer of lines; mutations edit that buffer; save() serializes it back with file_put_contents. If you skip load(), the buffer is empty and save() will truncate your .env to nothing. Wrap it in a service so nobody on the team calls it raw:

class EnvFile
{
    public function set(array $pairs): void
    {
        DotenvEditor::load();
        foreach ($pairs as $key => $value) {
            DotenvEditor::setKey($key, (string) $value);
        }
        DotenvEditor::save();
    }
}

Installer / setup wizard

The most defensible use. Collect DB and mail settings, write them, clear config, then redirect to a fresh request so the new values are read by a clean process:

$this->envFile->set($validated);
Artisan::call('config:clear');
Artisan::call('cache:clear');
return redirect('/login'); // new request reads the new .env

Do not try to reconfigure the current request's DB connection from the newly written file — set config() in memory if you must, but the redirect approach avoids a class of confusing bugs.

Admin settings panel

Split the page into "editable keys" and "everything else". Maintain an allowlist:

const EDITABLE = ['MAIL_HOST', 'MAIL_PORT', 'MAIL_USERNAME', 'MAIL_PASSWORD', 'MAIL_ENCRYPTION'];

Iterate the allowlist, skip keys whose submitted value is the placeholder mask (••••••••), so a password field left untouched doesn't get overwritten with literal bullets. This is the single most common bug in these panels.

Artisan command wrapper

Expose it to ops so nobody hand-edits production .env files:

// php artisan env:set MAIL_HOST smtp.example.com
DotenvEditor::load()->setKey($key, $value)->save();
$this->info("Set {$key}. Run `php artisan config:clear` on all nodes.");

Make the command dry-run by default (--force to write) and print a diff.

Backups

Before any write, copy .env yourself — don't assume the package does it:

File::copy(base_path('.env'), storage_path('app/env-backups/'.now()->timestamp.'.env'));

Keep a restore command. You will need it.

Testing

Point the editor at a fixture file rather than the real .env:

DotenvEditor::load(base_path('tests/fixtures/.env.testing'));

If the version you're on hardcodes base_path('.env'), bind the config or refactor the class to accept a path — worth the ten minutes.

Gotchas and Tips

Changes don't take effect in-process. env() reads the loaded repository and config() is populated at boot. Writing the file does nothing to the running app. You need config:clear (or config:cache if you're cached) plus a process restart for queue workers and Octane. If config:cache is in play in production, .env is not read at all — your writes are inert until you recache.

Quoting and escaping. Values with spaces, #, =, quotes, or newlines need to be wrapped. The package handles common cases but not all; validate at the boundary (reject whitespace-only, strip control characters) and after writing, reload the file and assert getKey() returns what you wrote. A silent round-trip mismatch is worse than a crash.

Comments and ordering. setKey rewrites the matching line in place and appends new keys at the end, preserving comments and order. setContent()/full-content writes will not. Prefer setKey/deleteKey over content rewrites, and don't be surprised when save() reflows a hand-formatted file.

Duplicate keys. If .env has MAIL_HOST twice, getKey returns the first and setKey updates the first; the second still wins at parse time in some loaders. Deduplicate as part of your write path or you'll chase a "my change didn't apply" ghost.

Concurrency. There's no file locking. Two simultaneous admin saves can interleave and corrupt the file. Serialize writes (a queue job with WithoutOverlapping, or a cache lock) and keep the operation rare — this is not a per-request write path.

Permissions. The PHP-FPM user must own or be able to write .env. Deploy tooling often sets 600 deploy:deploy, which silently fails for www-data. Check is_writable() and fail loudly with a message that names the file and user.

Security. An .env write endpoint is remote code execution waiting to happen (imagine APP_KEY, DB_HOST pointed at an attacker's MySQL, or a crafted value). Put it behind admin auth, CSRF, an allowlist, rate limiting, and audit logging of key + old/new value (redact secrets in the log). Never expose it in a public-facing app.

Package health. Last release 2018, zero dependents listed, and it's a fork. Budget for it to break on the next phpdotenv major. The mitigation is cheap: it's small enough to vendor, and if it ever blocks you, replacing it with a ~40-line class around Dotenv\Parser plus file_put_contents is an afternoon. Do that proactively if you're on Laravel 10+ and hitting constraint conflicts rather than pinning your way out of it.

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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core