Shift with red gradient lettering Skip to content

Deep Dive

Handling customizations when upgrading Laravel config files

For older versions of Laravel, Shift simply defaults your config files. It does so by overwriting them with their latest version. For example, if you are upgrading from Laravel 5.5 to Laravel 5.6, Shift will add the Laravel 5.6.33 versions of the config files to your project.

While this might work for some files, it's unlikely to work for all files. This is because config files are often customized. For example, the config/app.php, config/database.php, or config/mail.php are the most customized. If so, after running Shift, these files would get defaulted. A developer would then need to manually review them and bring over their customizations.

Now you might think, "That's not very automated. Why do it this way?"

Well, over the years I found that the config files are the most changed files within the Laravel skeleton. In fact, they change multiple times between releases. Options and values get added, changed, removed, even reverted time and again.

I've answered countless emails and paired with numerous developers who lost days on some obscure bug. The issue turned out to be a single incorrect configuration option.

So while not the most automated, Shift's choice to default the config files ensures the project contains the latest configuration options and values. This forces the developer to review and merge their changes. While manual, it's a straightforward task of scrolling through a commit diff. Likely taking a few minutes, instead of potentially losing days by not upgrading the config files properly.

Starting with Laravel 6, Shift does a better job automating the upgrade of config files. It does so by merging your options with the latest version of the config file. As before, Shift first defaults the config files to the latest versions. Then, Shift will review the options within your config files and merge any custom options.

The result is, more or less, the same as what a developer would get if they manually compared the files and merged their customizations into the latest version.

Now, there's a bit of nuance there. First analysis of PHP code is always tricky. The config files are pretty conventional out of the box. But developers can customize the syntax or indentation. They can also add logic, comments, or even remove options. If so, some of those customizations may still need to be done manually.

The other nuance, and this is the bigger one, Shift will not overwrite options which may be configured through default ENV variables. For example, when merging the config/database.php file, the Laravel 10.3.3 version contains the following line:

'default' => env('DB_CONNECTION', 'mysql'),

If the config/database.php file within a project contained the following customization:

'default' => env('DB_CONNECTION', 'pgsql'),

Or even:

'default' => 'pgsql',

Shift would not not merge this option. That is because it has a default ENV variable (DB_CONNECTION) which you may use to customize the configuration.

The motivation behind this comes from Shift's primary goal - to make upgrading your application easier. Not just for the current version, but also future versions. As we've learned, the config files change most often. By using the provided ENV variable, you do not need to change the config file. So that's one less change you'll need to review next time you upgrade Laravel.

Merging config files this way works for a far majority of projects. It's much more automated, and as such provides a better developer experience. But there still might be some manual work.

When you run Shift and it encourages you to use the ENV variables, you still need to review the commit diff to see which values you hardcoded.

With the new slim skeleton in Laravel 11, and its dozens of new ENV variables, you would really need to review the config files closely. Even if you had run Shift before and followed its recommendations, the likelihood of manual review would have been high.

So, for the Laravel 11.x Shift, I built a new feature to output the ENV variables you had customized. This appears as a comment on the pull request with a code snippet that is ready to copy and paste into your respective .env file.

For example:

BCRYPT_ROUNDS=10
CACHE_STORE=file
DB_CONNECTION=mysql
MAIL_MAILER=mailgun
QUEUE_CONNECTION=redis
SESSION_DRIVER=file

Building this feature didn't require as much code as I thought. I had already determined what options used ENV variables. This, like many things with Shift, was done using static analysis. Without getting deep into abstract syntax trees, I check if your configuration option value uses the env helper. If so, I inspect its arguments to check for customizations.

Going back to our example configuration:

'default' => env('DB_CONNECTION', 'pgsql'),

I see that this option is using the env helper, and I can parse out that the ENV variable name as DB_CONNECTION and the default value as pgsql.

I can also check this configuration option from the Laravel version to see it also uses the DB_CONNECTION ENV variable, but has a default value of mysql.

Since the values do not match, I add them to a customized list to later format and output in the PR comment.

This feature really rounds out one of the critical bits of automation when upgrading your Laravel application. Yet it still does so with an eye to the future. Laravel 11 has also shown a trend for moving away from managing full config files yourself. While still an option, you may now only manage your true customizations. Or even remove the config file and do configure everything through ENV variables.

This is another benefit of Shift. As we learn more about the future state of Laravel, I can go back and update previous Shifts and guide their automation closer to that state. In this case, all of the Laravel Shifts now leave this comment with any customized ENV variables and their values as it automates the upgrade of your config files.