envless/env is the Envless runtime for PHP. It fetches your environment when your app starts, decrypts it in the process, fills $_ENV, $_SERVER and getenv() with every name that is safe to set, and gives your code Env::get(), which reads each variable coerced to the type you set in Envless. No .env file holding secrets on disk, no vlucas/phpdotenv to keep in sync, no typo that only fails in production.
composer require envless/envuse Envless\Env\Env;
Env::load();
$databaseUrl = Env::string('DATABASE_URL');
$port = Env::get('PORT');It is the PHP twin of @goenvless/env: the same loader, the same on-disk cache, the same rules for the process environment and the same error messages. A parity check in the Envless repository replays every behaviour of both packages against one mock API before each release, from pagination and retries to the exact bytes of the cache file and which names are refused from the process environment.
What this is, and what it is not
envless/env | envless/sdk | envless run | |
|---|---|---|---|
| Purpose | Loads variables into your running app | Administers a workspace from PHP | Injects variables into any process |
| Runs | Inside your PHP process, at boot | In scripts, back offices and CI | In front of your process, as the launcher |
| Credential | A machine key and a decryption key | An API key | envless login, or a machine key |
| Shape | Env::get('DATABASE_URL') | $envless->variables->create(...) | envless run -- php artisan serve |
Use envless/env when your app should fetch its own variables at boot, typically in production with a machine key. Use envless run when you would rather keep every credential in the launcher. The two combine: inside envless run, envless/env reads the values the CLI injected and makes no request at all. envless/env installs the PHP SDK, envless/sdk, alongside, whose crypto helpers, Envless\Envless::encryptValue() and the rest, seal a value before you write it through the API.
The surface
| Call | What it gives you |
|---|---|
Env::load() | Loads once and returns every decrypted value as a plain array you own |
Env::get(), Env::optional(), Env::has() | Reads one variable, coerced to its declared type |
Env::string(), Env::number(), Env::boolean() | Reads one variable as that type, typed for PHPStan and Psalm |
Env::server() | Every variable, as an object you can read with ->, [] or foreach |
Env::client() | Only the variables marked client, safe to hand to a template or a browser |
Env::override() | Layers temporary values over the loaded ones, for tests |
Env::fetch() | Loads with every input as an argument, for serverless and multi-tenant code |
Env::isConfigured() | Whether a token is available, so a build without secrets can skip the load |
vendor/envless/env/register.php | Loads when it is included, for PHP's auto_prepend_file |
vendor/bin/envless-env types | Writes a typed class with one method per variable |
Envless\Env\Symfony\EnvVarLoader | Lets Symfony resolve %env()% from Envless |
Design
Typed reads
A number reads back as an int, or a float when it has a fraction, and a boolean as a bool. A missing name throws MissingVariableException instead of returning null, unless you read it with Env::optional().
Secrets stay put
json_encode() and serialize() refuse the server view, and var_dump(), print_r() and Laravel's dump() show names, never values.
Ambient wins
A variable already set in the process environment is never overwritten, and names that change how a process executes code, such as PATH, LD_PRELOAD or PHPRC, are never written at all.
Built for PHP-FPM
Every request reads a ciphertext cache shared with @goenvless/env, decrypts in microseconds with ENVLESS_KEY, and keeps serving the last values it had if the API is down.
Frameworks
Laravel
One guarded line in bootstrap/app.php, for env(), config(), Octane and queues.
Symfony
An env var loader for %env()%, or a load in the front controller.
PHP-FPM and plain PHP
auto_prepend_file, pool configuration, Apache and WordPress.
Serverless
Env::fetch() for Bref, Laravel Vapor and other functions.