skip to content

App Setup & Structure

Creating a Laravel app with the installer, the slim skeleton's folders, how public/index.php boots it, and .env-driven config. Interviewers open here to see if you know where things live.

on this pageshow

explore

questions

page 1 of 2

In a Laravel project, what is the difference between .env and .env.example, and which one belongs in version control?

level: juniorimportance: must knowfreq 68%

answer

  1. one is a template, one is real
  2. skeleton .gitignore lists .env
  3. copied on install if missing
  4. placeholders document required variables
  5. server variables beat .env values

basics

~10 s

.env holds this machine's real settings and secrets and is git-ignored; .env.example is the committed template listing every variable the app needs, with placeholder values. Laravel copies .env.example to .env on install.

solid answer

~40 s

Laravel reads per-machine settings from `.env` through the phpdotenv library, and the config files pull them in with `env()`. `.env` contains real values (database password, payment keys), differs per developer and server, and the skeleton's `.gitignore` excludes it. `.env.example` is the committed template: every variable the app expects, with safe placeholders, so a new teammate can see what to fill in. The skeleton's Composer scripts copy `.env.example` to `.env` when no `.env` exists (on `create-project` and in the `setup` script). When you add a variable, add it to `.env.example` in the same commit. Values are strings except the reserved words `true`, `false`, `null` and `empty`, and a variable already set in the real server environment wins over the same key in `.env`.

code

ini · 7 lines
ini
# .env.example (committed)
APP_NAME="Gym Pro"
APP_ENV=local
APP_DEBUG=true
DB_CONNECTION=sqlite
PAYMENT_API_KEY=
PAYMENT_WEBHOOK_SECRET=

go deeper

for a junior

Know which file is committed (.env.example) and which is git-ignored (.env), and that adding a new variable means updating the example file in the same change.

for a middle

Explain the Composer script that copies the template, the immutable repository that lets real environment variables win, and the reserved values env() converts to booleans and null.

for a senior

Treat an .env that reached Git history as a leaked set of credentials, and design deploys so production values arrive as real environment variables or through Laravel's encrypted environment files.

for a principal

Set a team rule that every new setting ships with its .env.example entry and a config file mapping, so onboarding and new environments never depend on someone's private notes.

## Two files with two jobs A Laravel app keeps anything that differs between machines out of its code and out of `config/*.php`. Those values live in a plain text file at the project root, parsed by the **phpdotenv** library at boot. | | `.env` | `.env.example` | |---|---|---| | Contains | real values for this machine | every variable name, with placeholders | | Secrets | yes (database password, payment key) | never | | In Git | no, the skeleton's `.gitignore` lists it | yes, committed and reviewed | | Read by Laravel at boot | yes, unless config is cached | no, it is only a template | | Who edits it | each developer or server | whoever adds or removes a setting | For a gym-membership app, `.env` on a laptop might point `DB_CONNECTION` at SQLite and hold a sandbox `PAYMENT_API_KEY`, while production has a different database and the live key. `.env.example` lists both variable names with dummy values. ## How a new clone gets its `.env` The laravel/laravel skeleton wires the copy into Composer: 1. `composer create-project` runs the `post-root-package-install` script, which copies `.env.example` to `.env` if no `.env` exists. 2. A teammate cloning an existing repo runs `composer run setup`; its steps include the same copy, then `key:generate` and the migrations. 3. The developer then edits `.env` with their own values. Because the copy only happens when `.env` is missing, it never overwrites someone's existing file. ## The format - One `KEY=value` per line; lines starting with `#` are comments. - Values containing spaces go in double quotes: `APP_NAME="Gym Pro"`. - Everything is a **string**, except reserved values that `env()` converts: `true`/`(true)` become boolean `true`, `false`/`(false)` boolean `false`, `null`/`(null)` become `null`, and `empty`/`(empty)` an empty string. - The config files decide the final type. The skeleton's `config/app.php` still wraps the debug flag in `(bool)` to be safe. ## Who wins when a variable is set twice Laravel builds phpdotenv's repository as **immutable**: loading `.env` never overwrites a variable that already exists in the process environment. So a `PAYMENT_API_KEY` set by the server, container or shell takes precedence over the line in `.env`. That lets a deployment platform inject secrets as real environment variables while developers keep using `.env` locally. ## Habits interviewers check - **Never commit `.env`.** If it was committed once, removing the file does not remove it from history; the values in it must be treated as exposed. - **Keep `.env.example` in step with the code.** A pull request that adds `env('PAYMENT_WEBHOOK_SECRET')` to a config file should add `PAYMENT_WEBHOOK_SECRET=` to `.env.example`; otherwise the next clone fails in a confusing way. - **Placeholders, not real values**, in the example file, even for "harmless" sandbox keys. - **Code reads `config()`, not `env()`.** The `.env` file feeds config files; application code reads the config keys. - **Environment-specific files exist too.** A `.env.testing` or `.env.staging` file can replace `.env` for that environment; which one loads depends on `APP_ENV` and the `--env` option. ## When a variable is missing If a variable is absent from both `.env` and the real environment, `env()` returns the default given in the config file, or `null` when there is none. That is why the config files carry sensible defaults for most values (`env('APP_ENV', 'production')`, `env('DB_CONNECTION', 'sqlite')`) and no default for secrets. A secret with no default fails as `null`, which is easier to spot than a wrong-but-plausible fallback. When the gym app adds a payment webhook, its config entry should read `env('PAYMENT_WEBHOOK_SECRET')` with no default, and `.env.example` should list the name with an empty value. A few more format details trip people up: - Spaces around `=` are not needed; write `KEY=value`. - Values containing spaces or a `#` are safest in double quotes, so the parser cannot mistake part of them for a comment. - Variables can reference earlier ones: `APP_NAME="Gym Pro"` then `MAIL_FROM_NAME="${APP_NAME}"`, as the skeleton's `.env.example` does. ## A small `.env.example` ```ini APP_NAME="Gym Pro" APP_ENV=local APP_DEBUG=true DB_CONNECTION=sqlite PAYMENT_API_KEY= PAYMENT_WEBHOOK_SECRET= ``` The empty values are deliberate: the names document the requirement, and each developer fills their own `.env`.

  • The server sets PAYMENT_API_KEY as an environment variable and .env also contains it. Which value does Laravel use?
    The server's. Laravel builds phpdotenv's repository as immutable, so loading `.env` never overwrites a variable already present in the process environment. The line in `.env` is simply ignored for that key. This is what lets a hosting platform inject production secrets while `.env` still works on laptops.
  • What does env() return for a .env line such as FEATURE_TRIALS=false?
    Boolean `false`, not the string "false". Laravel's `Env` class converts the reserved words `true`, `false`, `null` and `empty` (and their parenthesised forms) to real types. Any other value, including `0` or `yes`, comes back as a string, so cast it in the config file if you need a number.

saying these in an interview costs you the question

  • Commit .env so every developer shares the same settings
  • .env.example is loaded as a fallback when .env is missing
  • Values in .env always override server environment variables
  • FEATURE_TRIALS=false in .env returns the string 'false' from env()
  • Put real sandbox keys in .env.example for convenience
open as a page

In a fresh Laravel 13 application, what belongs in app, bootstrap, config, database, public, resources, routes and storage?

level: juniorimportance: must knowfreq 60%

basics

~20 s

app holds your classes, bootstrap boots the framework and keeps its caches, config holds settings arrays, database holds migrations, factories and seeders, public is the web root, resources holds views and raw assets, routes the route files, storage runtime files and logs.

open as a page

In a Laravel 13 app, what does `composer run dev` start, and why use it instead of running `php artisan serve` alone?

level: juniorimportance: must knowfreq 48%

basics

~20 s

composer run dev calls php artisan dev, which by default runs the PHP development server, a queue listener, Pail log tailing and the Vite dev server together. artisan serve alone only answers HTTP, so queued jobs and Vite assets are left without a process.

open as a page

In Laravel 13, how does `laravel new` differ from `composer create-project laravel/laravel` when you start a new application?

level: juniorimportance: must knowfreq 58%

basics

~20 s

composer create-project laravel/laravel copies the bare skeleton and runs its Composer scripts (.env, app key, SQLite file, migrations). laravel new wraps that step and adds prompts, an optional starter kit, Pest by default, a front-end build and Boost.

open as a page

In a Laravel 13 app, what do public/index.php and bootstrap/app.php each do when an HTTP request arrives?

level: juniorimportance: must knowfreq 52%

basics

~10 s

public/index.php is the entry point: it checks for maintenance mode, loads Composer's autoloader, requires bootstrap/app.php to get the application, and calls handleRequest(Request::capture()). bootstrap/app.php builds and returns that application with Application::configure()->...->create().

open as a page

In Laravel, what does php artisan vendor:publish copy, and how do its --tag and --provider options choose the files?

level: juniorimportance: must knowfreq 55%

basics

~10 s

vendor:publish copies files that service providers registered with publishes() into the app. --tag picks a named group of files, --provider picks one provider's files, and existing files are skipped unless --force is given.

open as a page

How often does Laravel ship a major release, and how long does each major receive bug fixes and security fixes?

level: juniorimportance: must knowfreq 55%

basics

~20 s

Laravel releases one major version a year, around the first quarter. Each major gets bug fixes for 18 months and security fixes for 2 years; Laravel 13 (March 2026) is covered for security until March 17th, 2028.

open as a page

In a Laravel gym-membership app, why does env('PAYMENT_API_KEY') in a controller return null in production while it works locally?

level: middleimportance: must knowfreq 78%

basics

~20 s

Production runs with cached configuration, and once config is cached Laravel skips loading .env, so env() sees only real server environment variables. Map the key in a config file and read it with config() instead.

open as a page

In Laravel 13, where do you configure what app/Http/Kernel.php, app/Console/Kernel.php and app/Exceptions/Handler.php used to hold?

level: middleimportance: must knowfreq 50%

basics

~10 s

Since Laravel 11 the skeleton has no kernel or handler classes. Middleware and exception handling are configured in bootstrap/app.php, schedules and closure commands go in routes/console.php, command classes in app/Console/Commands, and providers in bootstrap/providers.php.

open as a page

How does Laravel 13 turn an HTTP request into a response, from handleRequest() through the kernel and router to the controller and back?

level: middleimportance: must knowfreq 64%

basics

~20 s

handleRequest() passes the request to the HTTP kernel, which bootstraps the app and runs global middleware into the router. The router runs route middleware and the controller, converts its return value into a response, and handleRequest() sends it, then terminates.

open as a page

How does Laravel package auto-discovery register a package's service provider without anyone editing bootstrap/providers.php?

level: middleimportance: must knowfreq 58%

basics

~10 s

A package lists its providers and facade aliases under extra.laravel in its composer.json. package:discover reads every installed package's entry into bootstrap/cache/packages.php, and Laravel registers those providers at boot.

open as a page

How would you move a municipal permit portal from Laravel 10 to Laravel 13, and why upgrade one major at a time?

level: seniorimportance: must knowfreq 50%

basics

~20 s

Move PHP to 8.3 first, since Laravel 10 through 13 all support it, then upgrade 10 to 11, 11 to 12 and 12 to 13, following each upgrade guide and getting tests green after every hop.

open as a page

Why must a Laravel 13 app's web server document root point at public/, and what leaks if it points at the project root instead?

level: juniorimportance: should knowfreq 45%

basics

~20 s

public/ holds only the front controller index.php and assets, so every request goes through Laravel. Serving the project root lets browsers request files like .env with credentials and APP_KEY, storage/logs/laravel.log, composer.json and vendor code directly.

open as a page

In Laravel, where does app()->environment() get its value, and how does an externally set APP_ENV choose which .env file loads?

level: middleimportance: should knowfreq 48%

basics

~10 s

app()->environment() returns the app.env config value, which config/app.php takes from APP_ENV (default 'production'). An APP_ENV set outside the file makes Laravel load .env.{APP_ENV} instead of .env when that file exists.

open as a page

In Laravel 13, why does config('view.paths') return a value when config/view.php does not exist, and how do you change it?

level: middleimportance: should knowfreq 36%

basics

~20 s

Laravel 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.

open as a page

In a Laravel 13 school-timetable app, where should a stray helper file of timetable functions live, and what does Laravel need to find it?

level: middleimportance: should knowfreq 36%

basics

~20 s

Turn it into a class under app/, for example app/Support/TimetableFormatter.php in the App\Support namespace; PSR-4 autoloading of App\ finds it with no registration. Global functions need Composer files autoloading, and config/, routes/, bootstrap/ and public/ are the wrong places.

open as a page

For local Laravel development, how do Herd and Valet serve an app differently from `php artisan serve`, and what does parking a directory do?

level: middleimportance: should knowfreq 32%

basics

~20 s

Herd and Valet keep Nginx running in the background and resolve *.test names, so every app inside a parked directory is served at foldername.test with no command. php artisan serve starts PHP's single-process built-in server on 127.0.0.1:8000 only while it runs.

open as a page

With the Laravel 13 installer, what does `laravel new` choose by default for testing, database, Boost and npm, and which flags change each?

level: middleimportance: should knowfreq 30%

basics

~10 s

The Laravel 13 installer defaults to Pest, SQLite, Laravel Boost and npm. Override them with --phpunit, --database=mysql (or mariadb, pgsql, sqlsrv), --no-boost, and --pnpm, --bun, --yarn or --no-node.

open as a page

Which bootstrappers does the Laravel 13 HTTP kernel run, in what order, and why does that order matter to your own code?

level: middleimportance: should knowfreq 40%

basics

~10 s

LoadEnvironmentVariables, LoadConfiguration, HandleExceptions, RegisterFacades, RegisterProviders, BootProviders. So .env is read before config files, errors are handled before providers run, and every eager provider is registered before any provider boots.

open as a page

In a Laravel app, how do you stop package discovery from registering a particular package, and when would you want to?

level: middleimportance: should knowfreq 30%

basics

~10 s

List the package's Composer name under extra.laravel.dont-discover in the app's composer.json (or * to disable discovery entirely), rebuild the manifest with package:discover, and register the provider yourself where and when you want it.

open as a page

In a Laravel package's service provider, what do loadRoutesFrom() and loadViewsFrom() do, and how can an app override one of the package's views?

level: middleimportance: should knowfreq 35%

basics

~10 s

loadRoutesFrom() requires the package's route file unless routes are cached; loadViewsFrom() registers a view namespace such as audit-trail::. Laravel checks resources/views/vendor/audit-trail first, so a file placed there overrides the package's view.

open as a page

What did Laravel 11's slim application skeleton change for new apps, and does an app upgraded from Laravel 10 have to adopt it?

level: middleimportance: should knowfreq 45%

basics

~20 s

Laravel 11 gave new apps a much smaller skeleton: no app-level kernel classes, middleware and exceptions configured in bootstrap/app.php, one service provider, and opt-in config, API and broadcasting files. Upgraded apps may keep their Laravel 10 structure.

open as a page

Under Laravel's versioning scheme, what may a minor laravel/framework release such as 13.34 change, and why are named arguments a risk?

level: middleimportance: should knowfreq 32%

basics

~20 s

A minor release like 13.34 may add features and fix bugs but should never contain breaking changes; those wait for the next major. Named arguments are excluded from that promise, because Laravel may rename method parameters in any release.

open as a page

How do Laravel's env:encrypt and env:decrypt commands let a team commit its production environment file, and where must the key live?

level: seniorimportance: should knowfreq 26%

basics

~10 s

env:encrypt writes an encrypted copy such as .env.production.encrypted that can be committed; env:decrypt recreates the plain file during deployment. The key must stay outside the repository, typically in LARAVEL_ENV_ENCRYPTION_KEY on the deploy host.

open as a page

Why would a Laravel 13 app deployed from an image that dropped empty folders fail every page with 'Please provide a valid cache path', and what is missing?

level: seniorimportance: should knowfreq 28%

basics

~10 s

storage/framework/views is missing. The view config sets the compiled path to realpath(storage_path('framework/views')), which is false for a missing folder, so the Blade compiler throws. Recreate the storage and bootstrap/cache tree, writable by PHP.

open as a page

A new hire sets up your Laravel 13 veterinary-clinic booking app on a fresh laptop with PHP 8.2; what goes wrong, and how do you fix it?

level: seniorimportance: should knowfreq 28%

basics

~20 s

Laravel 13 requires PHP 8.3, so composer install on the cloned app fails its platform check, and a fresh laravel new or create-project quietly resolves Laravel 12 instead. Install PHP 8.3+ with the required extensions, including pdo_sqlite, then rerun setup.

open as a page

On a Laravel 13 ticket-resale site, a header set in a controller never reaches the browser; where in the lifecycle can the response still change, and where is it too late?

level: seniorimportance: should knowfreq 34%

basics

~20 s

Only the returned object becomes the response, and outbound middleware or exception rendering can replace it. It can change until send(), with a RequestHandled listener as the last hook; terminable middleware and terminating() callbacks run after send(), too late.

open as a page

In Laravel 13, what runs during the kernel's terminate() after the response is sent, in what order, and what are the pitfalls of work placed there?

level: seniorimportance: should knowfreq 28%

basics

~20 s

After send(), the kernel's terminate() dispatches the Terminating event, calls terminate() on terminable middleware, runs app()->terminating() callbacks (including afterResponse jobs), then runs slow-request handlers. The work cannot change the response and still holds the worker process.

open as a page

For an in-house Laravel audit-trail package used by three apps, should its migrations be loaded with loadMigrationsFrom() or published, and why?

level: seniorimportance: should knowfreq 26%

basics

~20 s

loadMigrationsFrom() runs the package's migrations straight from vendor/, so all three apps get new schema changes with each package update; publishing copies them into each app, which can then edit them but must re-publish to get later ones.

open as a page

In a Laravel package, why call mergeConfigFrom() in register(), and what goes wrong when an app's published config overrides a nested array?

level: seniorimportance: should knowfreq 38%

basics

~20 s

mergeConfigFrom() loads a package's default config under a key and lets the app's published copy override it. It merges only the first level, so a nested array in the app's copy replaces the package's whole.

open as a page

showing 1–30 of 33