Laravel: Store Settings in Database with Defaults in the config file

I personally prefer to have my site settings in the database to make them more customizable than to have them in the /config/settings.php file, Here’s how i do it:

assuming you want to have the file’s name settings.php inside the /config path, then whatever you put in there will be config(‘settings.some_option’);

return [
    'title'       =>'App Title',
    'description' =>'App Description',
    'performance' => [
        'cache'   => 1,
        'lifetime'=> 120,

That’s how my config file will look like, intentionally i had performance key as array for demostration.

Now i want to store these inside the database, and for that i have to create a migration (with or without model), preferably with a controller to keep things clean.

Do the php artisan make:migration SiteSettings -mc, that will generate the migration + the model + the controller

The Migration then should have two columns (option, value) [name them whatever you want].

public function up()
        Schema::create('site_settings', function (Blueprint $table) {

Now here come’s the actual work, we’re going to convert the config of /config/settings.php to flat array then store it as it is in the database, for that i used a snippet from stackoverflow.

 public static function prefixKey($prefix, $array)
        $result = array();
        foreach ($array as $key => $value) {
            if (is_array($value)) {
                $result = array_merge($result, self::prefixKey($prefix . $key . '.', $value));
            } else {
                $result[$prefix . $key] = $value;
        return $result;

That method will flatten the config and makes it compatible with how you usually retrieve keys from Laravel’s config() helper. Let’s say you want to retrieve the title from the config, we usually write it like that: config(‘settings.title’); and for something that is under performance we write it like that: config(‘settings.performance.cache’); but in order to make all this tree as one flat tree you need to use that function prefixKey (). that will make the config array looks like this


And that’s how you actually write the config syntax to retrieve something: config(‘performance.lifetime’) and we want to keep it like that.

Now that we made the settings configs flat we can insert them in the database, but before we do and make things too complex let’s do it from the controller through a method we call it init(), and in there we check and set the configs.

     * Initialize the config
     * @throws \Exception
    public static function init(): void

        # Just in case config('settings') doesn't exist
        if (is_array(config('settings'))) {

            # Create the default setting option if the key doesn't exist in database
            foreach (Helpers::prefixKey('', config('settings')) as $_key => $_value) {
                SiteSettings::firstOrCreate(['option' => $_key], ['value' => $_value]);

            # Retrieve the settings from database
            $Settings = SiteSettings::all()->pluck('value', 'option')->toArray();

            # Update the config helper to retrieve the database values
            # not the default values
            foreach ($Settings as $_option => $_value) {
                config(['settings.' . $_option => $_value]);

        } else {
            throw new \Exception('The config `settings` does not exist.');
  • First of all i loaded all the config(‘settings’) from the actual file located in /config/settings.php and made it flat array.
  • Insert SiteSettings DB row using the firstOrCreate because we don’t want to have two identical rows of the same settings. and we don’t want to use the updateOrCreate method because this row will be inserted from the default /config/settings.php key and not updated all the time, that’s how the file there becomes only for defaults and nothing more then it will be inserted in the database for future user updates.
  • Then we retrieve the Settings, make them as array[value=>option], that will make it well formatted to match the config default syntax.
  • Then we set the config(‘settings.*’) to use the database instead of the actual file.

Now for tests, try to to add a line in the actual config/settings.php, for example : ‘test’=>1 and run the init() method, That should add a row of that option in the database, now try to change the value of the test in the /config/settings.php file and try to output it using config(‘settings.test’) it will not show the updated value, but the database value. Try to change the value in the database and that should return the updated value. try to remove the row from the database and refresh, that should re-insert a db row of that missing value with the value set in /config/settings.php.

Now to make this check happens everytime without manually running the init() method, you can include that in the AppServiceProvider using : \App\Http\Controller\SiteSettingsController::init(); or whatever way you prefer.

That’s is, Hope you found this useful.