In Laravel 13, why does config('view.paths') return a value when config/view.php does not exist, and how do you change it?
answer
- the framework ships its own config/
- skeleton publishes only ten files
- your file merges over the framework's
- php artisan config:publish view
- config:show prints resolved values
basics
~20 sLaravel 13 loads the framework's own config files as a base and merges the app's files over them, so view settings exist without a local file. Run php artisan config:publish view to copy it into config/ for editing.
solid answer
~40 sSince Laravel 11 the skeleton ships only the config files most apps edit; in Laravel 13 that is ten (`app`, `auth`, `cache`, `database`, `filesystems`, `logging`, `mail`, `queue`, `services`, `session`). `laravel/framework` carries a full `config/` directory of its own, and the configuration bootstrapper loads those files as a **base**, then merges each app file over it with `array_merge`. So `view`, `hashing`, `concurrency` and `broadcasting` resolve from the framework copy until you override them. If the setting you need already reads an environment variable (`view.compiled` reads `VIEW_COMPILED_PATH`), set the variable; otherwise `php artisan config:publish view` copies the framework file into `config/view.php` (`--all` copies every missing one, `--force` overwrites). `php artisan config:show view` prints the values the app actually resolved, and it also accepts a single key such as `config:show services.payment`.
code
bash · 4 linesphp artisan config:show view
php artisan config:publish view
# add resource_path('branch-views') to 'paths' in config/view.php
php artisan config:show view.pathsgo deeper
Know that config:publish copies a missing config file into config/ and that config:show prints the values the app is using.
Explain the base-and-merge loading: framework files first, the app's files merged over them, with a one-level-deeper merge for connections, stores, disks, channels and mailers.
Prefer an existing environment variable over publishing, publish only files you change, review published copies after each major upgrade, and use config:show on a server to settle what value is live.
Set a policy for which config files a team's apps may publish, so upgrades stay small and differences between apps are deliberate rather than accidental copies.
## Two config directories, one repository A Laravel 13 app has two sources of configuration files: - **`config/` in the application.** The laravel/laravel skeleton ships ten files: `app`, `auth`, `cache`, `database`, `filesystems`, `logging`, `mail`, `queue`, `services` and `session`. - **`config/` inside `laravel/framework`.** It holds a complete set, including files the skeleton leaves out: `broadcasting`, `concurrency`, `cors`, `hashing`, `images` and `view`. This split started with Laravel 11's slim skeleton. Before that, a new app received every config file, most of which nobody edited. ## How the files are merged When configuration is loaded (and there is no config cache), the bootstrapper does roughly this: 1. Load every framework config file into a **base** array, keyed by file name. 2. For a framework file with **no** app counterpart, put the framework array into the repository unchanged. That is why `config('view.paths')` returns `[resource_path('views')]` with no `config/view.php`. 3. For an app file that **does** have a framework counterpart, `array_merge` the app array over the base. Your top-level keys win; keys you omit keep the framework's value. 4. For a few nested options the merge goes one level deeper, so the framework's named entries survive next to yours: | File | Options merged one level deeper | |---|---| | `auth` | `guards`, `providers`, `passwords` | | `broadcasting` | `connections` | | `cache` | `stores` | | `database` | `connections` | | `filesystems` | `disks` | | `logging` | `channels` | | `mail` | `mailers` | | `queue` | `connections` | So deleting the `pgsql` entry from your `config/database.php` does not remove the connection: the framework's `pgsql` connection is merged back in. Defining your own entry with the same name replaces the framework's entry as a whole. An application can opt out with `dontMergeFrameworkConfiguration()` on the application instance, in which case only its own files are loaded. ## Change it without publishing, when you can Many framework config values already read an environment variable. The framework's `view.php` has two keys: - `paths`: a plain array, `[resource_path('views')]`, with no `env()` call. - `compiled`: `env('VIEW_COMPILED_PATH', realpath(storage_path('framework/views')))`. To move compiled templates, set `VIEW_COMPILED_PATH` and publish nothing. To add a second view directory, there is no variable, so you publish the file. ## Publishing a file with `config:publish` ```bash php artisan config:publish view # copy one file php artisan config:publish # choose from a list php artisan config:publish --all # copy every framework file php artisan config:publish view --force # overwrite an existing copy ``` - The command copies the framework's file into `config/` so you can edit it. - An unknown name prints "Unrecognized configuration file." and the command fails. - If the file already exists it refuses unless you pass `--force`. Publish only the files you change. A published file is a snapshot: later framework releases may add keys to their copy, and your copy will not show them (the merge still supplies top-level keys you omit, but readers of your file will not see them). ## Inspecting what resolved with `config:show` `php artisan config:show view` prints the resolved values of a file in dot notation, after the merge and after `env()` calls. It also takes a single key, such as `config:show view.paths`. If the file or key does not exist in the repository, the command fails with a "does not exist" message. ## A gym-membership example The gym app keeps branch-specific email and page templates in `resources/branch-views` and wants Blade to find them: 1. Run `php artisan config:publish view`. 2. Add `resource_path('branch-views')` to `paths` in the new `config/view.php`. 3. Run `php artisan config:show view.paths` to confirm the two directories. ## Why the design changed Before the slim skeleton, every app carried dozens of config files it never touched, and each upgrade guide asked teams to diff them against the new release. Moving the defaults into the framework means an untouched setting follows the framework automatically, and the `config/` directory of an app shows only what that team chose to change. The cost is discoverability: a developer who looks for a setting in `config/` and does not find it has to know that `config:show` or the framework's own file is the place to look. ## Points interviewers probe - A missing config file is not a missing setting; the framework supplies it. - Check for an existing environment variable before publishing a file. - Publishing is a copy, not a link. - The merge is shallow except for the named options above. - `config:show` answers "what value is the app really using?" faster than reading files.
- A published config/database.php no longer lists the pgsql connection. Can the app still use it?Yes, while framework config merging is on. For `database`, the `connections` option is merged one level deep, so the framework's `pgsql` entry is added back next to yours. Only an entry you define with the same name replaces the framework's. Calling `dontMergeFrameworkConfiguration()` on the application turns the merge off.
- Why not just run config:publish --all in every new app?It adds files the team never edits, and each one is a snapshot that stops showing keys the framework adds later. Keeping only the files you change makes intent visible in review and keeps upgrades smaller. `config:show` gives you the resolved values of any unpublished file when you need to read them.
saying these in an interview costs you the question
- A missing config/view.php means the view settings are undefined
- config:publish creates a link that tracks framework updates
- Removing a connection from config/database.php deletes it from the app
- You must publish a config file even to change a value it reads from env()
- config:show reads the raw PHP file without env() values