FireWire Posted March 3 Posted March 3 Hello! I use .env files on every ProcessWire project to manage environment-specific configurations and settings. I've built a ProcessWire specific utility that makes using .env files a breeze. This post isn't intended to debate .env vs. config.php, use what you're comfortable with and prefer. That said, here are a few benefits to using .env files that may make it worth considering: Native support on web servers, including Apache, they are not served via http request by default True environment based secrets and settings management A standard file widely used and accepted as the method for managing secrets and sensitive values Able to store any value whether sensitive or not and access them globally Building a dedicated solution came from a discussion here on the forums where I threw together a rough implementation that needed little polish for real world use. It makes use of phpdotenv. This utility delivers the following: Easy use of and access to .env variables Caching the parsed .env for performance. This is a significant part of this utility and addresses a known need Automatic .env change recognition and re-caching Utilities to make working with environment variables feel ProcessWire native and a few extra nifty things What it isn't: A module. It's not possible to make a module for this need because the information kept in a .env file needs to be available before ProcessWire boots. Adding this to a new or existing project is very easy. It's designed to implement quickly and use immediately in your projects. Full documentation is provided in the Github repository. Here are a few examples of using this tool: <?php namespace ProcessWire; use Env\Env; if(!defined("PROCESSWIRE")) die(); $env = Env::load(__DIR__ . '/../'); // Make env available throughout the application $config->env = $env; $config->dbName = $env->get('DB_NAME'); $config->dbUser = $env->get('DB_USER'); $config->dbPass = $env->get('DB_PASS'); // Env::get() takes a second argument that is the fallback value if for any reason DEBUG doesn't exist $config->debug = $env->get('DEBUG', false); // Conditional values. By default, if the condition is falsey, Env::if() returns null $config->adminEmail = $env->if('APP_ENV', 'production', 'you@youremail.com'); // A fourth argument will be returned if condition is false, truthy/falsey output can be env var names or specific values $config->adminEmail = $env->if('APP_ENV', 'production', 'ADMIN_EMAIL', 'you@youremail.com'); // Conversely, you can also check if a condition is not met. $config->adminEmail = $env->ifNot('APP_ENV', 'development', 'ADMIN_EMAIL'); // Use one env value to set multiple config properties $config->advanced = $env->if('APP_ENV', 'production', false, 'ENABLE_ADVANCED'); // Never in production, change locally in env as needed $config->adminEmail = $env->ifNot('APP_ENV', 'development', 'ADMIN_EMAIL'); // Never send an email in dev, always on staging/production These helper methods make is very straightforward to implement a dynamic config file. This can be useful for using secure .env values while retaining the ability to commit and upload some types of changes to your config.php file without needing to touch .env values on the server. You can also use Env::pushToConfig(). As long as you use the "screaming snake case" naming convention for your environment variable names, type and value recognition are handled automatically. <?php $env->pushToConfig($config, [ 'usePageClasses' => true, 'templateCompile' => 'TEMPLATE_COMPILE', 'debug' => ['DEBUG', false], // Fallback to false 'advanced' => $env->if('APP_ENV', 'production', false, 'ENABLE_ADVANCED'), 'adminEmail' => $env->ifNot('APP_ENV', 'development', 'ADMIN_EMAIL'), 'httpHosts' => [ 'something.com', 'staging.something.com', 'something.ddev.site' ], ]); Using Env in your application files and templates can be very useful. In the above example we assigned the Env object to $config->env. This lets you access your .env variables globally and use some helpful methods. <?php if ($config->env->eq('APP_ENV', 'development')): ?> <script src="/some/development/stuff.js"></script> <?php endif ?> <?php if (!$config->env->exists('GOOGLE_API_KEY')) { $wire->error('A Google API key could not be loaded from the environment file.'); } try { // Do something that could fail } catch (Exception $e) { $message = $config->env->if('APP_ENV', 'production', 'Oh no. Friendly message here', $e->getMessage()); } This utility also automatically casts 'true' and 'false' values in .env files to booleans, and casts numbers to integers. It also includes several configuration options. I have been using this tool in production and have been happy with it. Maybe you might find it helpful in your projects as well. If you like it, throw a star on the repo. If you run into any bugs, file an issue on Github. I may publish it as a composer package at some point. Env utility for ProcessWIre on Github. 11 1
elabx Posted March 3 Posted March 3 I have been using .env but only with phpdotenv, this looks like a step forward, thanks! 1
elabx Posted March 3 Posted March 3 Where would you recommend to place the Env folder? Is PW's .htaccess ready for it?
FireWire Posted March 3 Author Posted March 3 @elabx Same here, once I stumbled across that Github issue with performance I wanted to implement caching. There were a couple of places I needed to access env variables elswhere in my code, so this all grew out of some real world experience. I have my env folder in the root directory. The folders in the repo come with .htaccess files already placed which block access to any assets via http request, no need to make any changes to the ProcessWire .htaccess file. This can be used without any changes to ProcessWire itself. 1
FireWire Posted March 3 Author Posted March 3 5 minutes ago, elabx said: hadn't noticed the .htaccess files @elabx Those are really just a matter of being thorough with security. Another answer to your question about where to put the env folder is anywhere you want really. As long as you update your composer.json file so the namespace resolves to the location that folder you can keep it anywhere. 1
bernhard Posted July 24 Posted July 24 Hey @FireWire this is a really cool class! @Sanyaissues recommended it, so I had a closer look. I added it to RockShell (experimental) here: https://github.com/baumrock/RockShell/tree/env And I have added this little improvement: https://github.com/baumrock/RockShell/blob/7605dcaad6f0b009e01039405936aad825dc47c5/Env/Env.php#L37-L39 Then I added this test command: https://github.com/baumrock/RockShell/blob/env/App/Commands/EnvTest.php What I do not understand: It creates the file RockShell/Env/cache/env.php to cache the results. Does that mean that your class only supports reading from one single .env file system wide? What if I loaded another .env file from another folder? Would that be cached somewhere else or would that overwrite my existing .env file? Or is it maybe the point to always ever only have one .env file for the project? Never used .env before, sorry 🙂 1
FireWire Posted July 29 Author Posted July 29 @bernhard Glad you found it useful! On 7/24/2025 at 1:29 PM, bernhard said: Does that mean that your class only supports reading from one single .env file system wide? Yes. The logic behind .env files is that they are tied to the environment/server, not the application, so 1 environment = 1 .env file. Think of it as the store of values necessary for your application to run in a given environment. Your application doesn't have to care where it's being run, it just knows that the necessary values will be provided and everything works. On 7/24/2025 at 1:29 PM, bernhard said: Would that be cached somewhere else or would that overwrite my existing .env file? It would overwrite the cached file since the Env utility follows the general single-file usage of .env files Out of curiosity, how would multiple .env files be useful? 1
bernhard Posted July 29 Posted July 29 @Sanyaissues and I have been working intensively on a new version of RockMigrations Deployments, which will be moved to RockShell and will support Github Environments. So we thought about having an .env file per environment instead of prefixing every variable: // STAGING.env dbHost=localhost dbName=db_staging dbUser=whatever dbPass=1234 vs STAGING_dbHost=localhost STAGING_dbName=db_staging STAGING_dbUser=whatever STAGING_dbPass=1234 PRODUCTION_dbHost=localhost PRODUCTION_dbName=db_production PRODUCTION_dbUser=whatever PRODUCTION_dbPass=1234 But at the moment I decided to go with PHP files, so there is no need to change anything in your library 🙂 Thx for the explanation! 1
FireWire Posted July 29 Author Posted July 29 @bernhard Sounds good! To add to the greater conversation, here's how a .env file approach would work. A .env file is created for your local development. A .env file is created on a staging server if one is used. A .env file is created for the production server. Each file exists where they will be used and the values match the requirements for the application to run in that location. Since the .env file for a project is not committed to the repository, a commonly adopted way to document what is needed in it is to create a .env.example file that contains all of the variables used by the application without values. This is unrelated to @bernhard's reply but I didn't share some ProcessWire specific information in my original post that readers- whether choosing to use .env or not- may want to keep in mind. .env files are part of a secrets management strategy. Sensitive values should be stored in a separate location, like a password manager. The config.php file is a sensitive document. ProcessWire provides direction on securing the file on your server, however this doesn't account for workflows like Git or sharing config.php in collaborative situations. Sensitive values committed to a repository (even if it's private) must be considered compromised. It's not just about DB credentials. Here's an example: /** * Installer: User Authentication Salt * * This value was randomly generated for your system on 2023/02/22. * This should be kept as private as a password and never stored in the database. * Must be retained if you migrate your site from one server to another. * Do not change this value, or user passwords will no longer work. * */ $config->userAuthSalt = "c187bd9fx935ca861f43da592475fe6afa20a63"; Ryan's note says "private as a password", and that's real. Your auth salt must remain the same regardless of where your code is being run so it is a universally sensitive secret whether local, staging, or production. This unique value is part of how ProcessWire hashes passwords in the database. Having a config.php file committed in a repo with this value means that your site/app is now insecure. Removing it from your repo and pushing the change will not make it secure since it's in the commit history. So now you're faced with the situation of storing that value in addition to your database credentials which change depending on where your site/app is running. That's makes a case for a .env file or a secure solution like @bernhard is developing for his workflow implementation. 2
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now