The configuration workflow in Magento 2 is pretty amazing, because it can be controlled globally, per domain, per site, or even down to a specific environment. This fallback process is generally unknown though, and becoming familiar with it can help you out when crafting our solutions for your clients, or architecting that custom Magento module for distribution.
Basic global configuration
Let's start by taking a look at an example of a typical basic global configuration. Assume we are trying to implement a "dark mode" feature on the frontend of our website, and we'd like a configuration setting to control this feature globally on our site.
We'd start by creating a module, if we don't already have one. Then we'd create a simple configuration definition within an adminhtml/system.xml
file:
This will create a new "Dark Mode" group at Stores > Configuration > General > Web, with an "Enable?" Yes/No dropdown:
That is all that is needed to create a new "system config" key and value!
It's important to note where exactly in the XML tree we are placing this configuration option. A great practice to follow is avoiding creating additional admin groups & sections if at all possible, so you can retain a clean admin interface. Since the General > Web section already exists, this is a great place to collate our custom configuration option.
We can convert the nested nodes into a path to reference our configuration option. Naturally, the path for this Dark Mode configuration can be referenced with:
You can break out of this default location by defining a
config_path
node containing the full path location of where you wish to store this config.For example, if we wish to store this value at
acme/darkmode/enable
rather thanweb/darkmode/enable
, we can add a node as a child to thefield
node with the contents:<config_path>acme/darkmode/enable</config_path>
We have not yet set a default value for this configuration. We can do this by creating a new config.xml
file within our module, and reference the path of our new configuration property:
Since a configuration property has been defined and a default value set, we can now reference this configuration programmatically.
A quick way to check this would be using n98magerun2's dev:console
command:
...which outputs:
If you are using docker-magento for your development environment, you can also use
bin/devconsole
as a shortcut for then98magerun2 dev:console
command.
Configuration scope for websites and stores
The setup we created above defines a "global" configuration property. We can also have configurations related to a specific website or store.
For now, Dark Mode is set to a global "No" value. However, the additions above now allow Dark Mode to be configured from the admin after selecting a scope other than "Default":
If we wished to change the default configuration value for a specific scope, we can also add a secondary value to our module's config.xml
file:
The code above targets the "base" website. You can find the code to use for this value by going to Admin > Stores > Settings > All Stores, and looking at the values from the "Web Site" column for the "code" to target.
Similarly, you can target a specific store by using the stores
node in tandem with the related "code" from the "Store" column data.
All of the
config.xml
files in Magento are merged into one giant XML tree. If you wish to override third-partyconfig.xml
files, you can use the<sequence>
node in your module'smodule.xml
file to control the load ordering of modules. This controls the precedence of how XML nodes are merged together.The last value in an XML tree always has precedence, so make sure your module loads "after" others to take control of the value you are targeting.
Database configurations take precedence
As of right now, all configuration properties are using the default values. But if we change & save a configuration value from the admin, it will save the value to a new row in the core_config_data
database table.
The last record in the core_config_data
database table stores the path of web/darkmode/enable
with the value of 1
set for the default
scope.
Note that for
websites
andstores
scopes, the database uses thescope_id
with the numeric representation of the related scope.You can find this numeric id in the
store
andstore_website
database tables.
Once the data is saved in the database, it can additionally be retrieved using the built-in bin/magento
command with:
This command will return 1
, which is the value retrieved from the core_config_data
database table for this property. It will not a return a value if there are no related records that exist in this database table.
We can also set a value for this configuration property by using the config:set
command:
Upon refreshing the contents of the core_config_data
records, we'll see that the record for this property did indeed update:
We can use the --scope
and --scope-code
command parameters to define a scope other than "default".
For example, we can set a value for the "base" website with:
As expected, this creates yet another database record in the core_config_data
table for the scope that was passed in. Note that the scope_code
is translated into the numeric representation for that code at the time of insertion:
Values in the core_config_data
database table always override values defined in the PHP or XML layer. This provides a fallback mechanism, but there are additional fallback processes in place for environment management.
config.php overrules database configurations
Magento defines "shared-configuration" settings within the file at app/etc/config.php
.
This file is committed to version control, and is shared among all environments. The configurations are stored in a multi-dimensional array under the system
index in the format:
This example uses the websites
scope, however you can also target default
or stores
scopes as well. Be sure to write all configuration values as either null
or a string, even integer values such as the one above.
After adding or changing a value within this file, you'll notice an error on the frontend of your Magento site:
Magento detects mismatches between changes of value in your database compared to this file. The fix is easy though, just run:
After importing these values, any code looking up the value for this configuration property will return the value as expected. However, it's important to know that the core_config_data
table will not be updated with values from the import.
Again testing with n98magerun2 dev:console
:
...outputs:
=> [
"enable" => "0",
]
There appears to be a bug with the
bin/magento
script when retrieving the value with a specific scope, asbin/magento config:show --scope=websites --scope-code=base web/darkmode/enable
returns1
. This was found during the writing of this article, and a bug will be filed with the Magento 2 GitHub repo shortly.
Defining a value within the config.php
file will lock the value from being edited in the admin:
This is useful if you wish to hard-code a value for a specific configuration property and scope, and not allow it to be controlled by an admin user.
There's yet another level of precedence though over config.php
files...
env.php overrules config.php
The app/etc/env.php
file acts in an extremely similar manner to the app/etc/config.php
file, using the same format:
There is a big difference between config.php
and env.php
though, and that is the env.php file is not committed to version control, and this file is not shared among environments.
This allows you to define environment-specific changes to a configuration property value, so different environments can have different values. Similarly to config.php
, values defined in env.php
files are locked and are not editable from the admin.
Environment variables have the final word
Just when you thought this article was over, there is yet one more precedence to the fallback of a Magento configuration, and that is the use of an environment variable. This functions just like the env.php
file, but doesn't need to be set within this file. This can be useful with ephemeral, read-only servers, as well as some other specific cases.
Like everything else in Magento, setting a configuration value with an environment variable follows a very specific naming convention.
For default-scoped configurations:
...and for websites
or stores
scopes:
For our Dark Mode configuration property, this would be set with:
You can read in the DevDocs about extended usage of environment variables to override configuration settings.
Conclusion
I hope you learned at least one new thing about the Magento configuration by reading this article.
If you liked it, please share it with your fellow Magento developers! You may also sign up below to get notified about new Magento-related blog posts.
Intrigued to learn more about Magento? Experience these 3 helpful things that can help you:
- Explore Magento 2 fundamentals & best practices course (1,000+ students)
- Grow your Magento expertise with all courses & lessons (700+ students)
- Learn visually with blocks of code & inline comments (3,000+ students)