skip to content

Artisan & Dev Tools

Laravel's developer tools are Artisan's built-in and custom commands, the Tinker REPL, Sail's Docker environment and the Pint formatter. Interviewers ask how you use them day to day.

on this pageshow

explore

questions

20

In Laravel, how do `php artisan list`, `php artisan help` and `php artisan about` help you get oriented in an unfamiliar application?

level: juniorimportance: must knowfreq 55%

answer

  1. three read-only commands, three scopes
  2. inventory grouped by namespace
  3. list make narrows to one namespace
  4. help: arguments, options, global flags
  5. about --only=environment, --json

basics

~10 s

php artisan list prints every registered command grouped by namespace, php artisan help <command> shows one command's arguments and options, and php artisan about summarises versions, environment, debug mode, cache status and drivers.

solid answer

~40 s

`php artisan list` prints every command the application has registered — the framework's, installed packages' and the team's own — grouped by namespace, and `php artisan list make` narrows it to one namespace. `php artisan help migrate` (or `php artisan migrate --help`) prints one command's description, usage, arguments and options, generated from its signature, plus the global options such as `--env`. `php artisan about` is the snapshot: Laravel, PHP and Composer versions, environment, debug and maintenance mode, whether config, events, routes and views are cached, and which cache, database, queue, session, mail and log drivers are configured. `--only=environment,drivers` filters the sections and `--json` exports them. On an unfamiliar app I run `about` first, then `list` to find the team's custom commands, then `help` on anything before I run it.

go deeper

for a junior

Recall the three commands and what each prints: list for the inventory, help for one command's arguments and options, about for versions, environment, cache status and drivers.

for a middle

Explain that help is generated from the command's signature, that list groups by namespace and skips hidden commands, and what about's Environment, Cache, Drivers and Storage sections mean.

for a senior

Show an inspection routine: about --json on each server to compare drivers and cache state, list to find a legacy team's own commands, help before running anything that writes.

for a principal

Treat list and about as cheap onboarding and audit tools, and argue for commands with real descriptions so the Artisan listing stays a trustworthy map of team tooling.

## What Artisan is **Artisan** is the command-line interface every Laravel application carries as the `artisan` script in its root directory. Running `php artisan <command>` boots the real application — the same `bootstrap/app.php`, service providers and configuration a web request uses — registers every console command that the framework, the installed packages and the application define, and then runs the one you named. Because it boots *this* application, the answers Artisan gives describe this codebase and its configuration, not the framework's defaults. That makes three read-only commands the natural first stop when you open a project you did not write: `list`, `help` and `about`. ## `php artisan list`: the command inventory `php artisan list` (running `php artisan` with no command does the same) prints every registered command with its one-line description, grouped by **namespace** — the part of the name before the colon: - Framework namespaces such as `make`, `migrate`, `db`, `model`, `queue`, `route`, `schedule`, `config` and `cache`. - Commands registered by packages, for example the `sail:*` commands once Sail is installed. - The application's own commands: classes in `app/Console/Commands`, which Laravel registers automatically, and closure commands defined with `Artisan::command()` in `routes/console.php`. - `php artisan list make` narrows the output to a single namespace; in Laravel 13 the framework alone contributes 37 `make:*` generators, and packages can add more. One caveat: a command can be marked **hidden** — the `$hidden` property or the `#[Hidden]` attribute — and then it is left out of the listing while still running when called by name. `list` is an inventory of *advertised* commands, not proof that nothing else exists. ## `php artisan help <command>`: one command's contract `php artisan help migrate`, or equivalently `php artisan migrate --help`, prints the command's description, a usage line, and every argument and option with its description and default. The text is generated from the command's **signature**, so it cannot drift from the code the way a wiki page can. The same screen lists the **global options** every command accepts, including: - `--env`, which sets the environment the command runs under; - `-n` / `--no-interaction`, which suppresses questions; - `-q` / `--quiet` and the `-v` / `-vv` / `-vvv` verbosity levels. Reading `help` before running an unfamiliar custom command is cheap insurance: a legacy `orders:fix` might take a `--commit` switch you really want to know about first. ## `php artisan about`: the application snapshot `about` gathers facts from the booted application and prints them in sections: | Section | What it reports | |---|---| | Environment | application name, Laravel, PHP and Composer versions, environment name, debug mode, URL, maintenance mode, timezone, locale | | Cache | whether config, events, routes and views are `CACHED` or `NOT CACHED` | | Drivers | the configured broadcasting, cache, database, log, mail, queue and session drivers, plus Octane and Scout when set | | Storage | whether each configured public storage link exists (`LINKED` / `NOT LINKED`) | - `--only=environment,drivers` limits output to the named sections (comma-separated). - `--json` prints the same data as JSON — useful for pasting into a ticket or diffing two servers. - Packages can append a section with `AboutCommand::add('Billing', fn () => [...])`, usually from a service provider's `boot()` method. Note what the Cache section means: it says whether the *framework's* configuration, route, event and view caches are built, not what your cache store holds. ## A day-one routine for an unfamiliar app 1. `php artisan about` — which Laravel and PHP versions, which environment, whether debug is on, which drivers the team chose. 2. `php artisan list` — scan for namespaces that are not the framework's: those are the team's own scripts and the best map of what they automate. 3. `php artisan help <command>` on each unfamiliar custom command before running it. 4. Only then move on to schema and model inspection with the database commands. ## Caveats worth knowing - All three commands report what the **CLI process** resolves. If the web server supplies different environment variables, the web application can behave differently from what `about` printed. - `NOT CACHED` in the Cache section on a production server is a finding worth raising with whoever owns deployment. - None of the three changes anything: they are safe on any server, which is exactly why they come first.

  • How can a package add its own lines to `php artisan about`?
    It calls `AboutCommand::add()`, usually in its service provider's `boot()` method, with a section name and either an array or a closure returning key/value pairs — for example `AboutCommand::add('Billing', fn () => ['Gateway' => config('billing.gateway')])`. The closure runs when `about` runs, so the values are current, and the new section can be selected with `--only`.
  • Why might a custom command exist and run, yet not appear in `php artisan list`?
    It is probably marked hidden — `protected $hidden = true` or the `#[Hidden]` attribute. Hidden commands are left out of the listing but still execute when called by name, which teams use for internal or one-off tooling. So `list` shows advertised commands; searching `app/Console/Commands` and `routes/console.php` is how you find the rest.

saying these in an interview costs you the question

  • php artisan list shows only framework commands, never the app's or packages' commands.
  • A command missing from php artisan list cannot exist or be run.
  • php artisan about clears caches or otherwise changes the application.
  • The Cache section of about shows what the cache store currently holds.
  • You must read a command's source code to learn its arguments and options.
open as a page

In Laravel, what do the `make:*` Artisan generators do, and what does `php artisan make:model Shipment -a` create?

level: juniorimportance: must knowfreq 65%

basics

~10 s

make:* commands generate boilerplate classes from stub templates into the conventional folders. make:model Shipment -a also creates a migration, factory, seeder, policy and a resource controller wired to StoreShipmentRequest and UpdateShipmentRequest.

open as a page

In Laravel 13, how do you create a custom Artisan command with `make:command`, and how are its signature, description and `handle()` wired up?

level: juniorimportance: must knowfreq 65%

basics

~10 s

php artisan make:command ResendFailedInvoices writes a class to app/Console/Commands, which Laravel registers automatically. Its #[Signature] attribute names the command and declares input, #[Description] feeds the listing, and handle() does the work with container-injected services.

open as a page

What is Laravel Pint, and how do you run it to fix the code style of a Laravel application?

level: juniorimportance: must knowfreq 55%

basics

~20 s

Laravel Pint is an opinionated PHP code style fixer built on PHP CS Fixer and shipped as a dev dependency of new Laravel apps. Running ./vendor/bin/pint rewrites your PHP files to the laravel preset; adding --test only reports.

open as a page

What is Laravel Sail, and how do you add it to a Laravel 13 application and start its containers?

level: juniorimportance: must knowfreq 50%

basics

~20 s

Laravel Sail is a bash script plus a generated compose.yaml that runs the app and its services in Docker. In Laravel 13 you run composer require laravel/sail --dev, then php artisan sail:install, then ./vendor/bin/sail up.

open as a page

In a Laravel command signature, how do you declare required, optional, defaulted and array arguments, and switch versus value options with shortcuts?

level: middleimportance: must knowfreq 45%

basics

~20 s

In a Laravel signature, {customer} is required, {customer?} optional, {customer=5} defaulted and {customer*} an array. {--dry-run} is a true/false switch, {--limit=} takes a string value, {--limit=50} has a default, {--L|limit=} adds a shortcut and {--id=*} repeats.

open as a page

What is `php artisan tinker` in a Laravel application, and what should you watch out for when using it against real data?

level: juniorimportance: should knowfreq 50%

basics

~20 s

php artisan tinker opens a PsySH-based REPL with the whole Laravel application booted, so Eloquent, facades and services work interactively. It uses the same configuration and database as the CLI, so every write is real.

open as a page

With Laravel Sail, why run `sail artisan migrate` rather than `php artisan migrate`, and what do `sail composer`, `sail npm` and `sail test` do?

level: juniorimportance: should knowfreq 45%

basics

~20 s

Sail's commands run inside the laravel.test container, where the pinned PHP runs and hosts like mysql resolve. Host php artisan migrate uses the host's PHP and cannot reach DB_HOST=mysql; sail composer, npm and test do the same in the container.

open as a page

On day one with an unfamiliar legacy Laravel app, how would you use `db:show`, `db:table` and `model:show` to understand its data layer?

level: middleimportance: should knowfreq 30%

basics

~20 s

db:show summarises the database — engine, version, open connections and every table with its size; db:table details one table's columns, indexes and foreign keys; model:show joins a model's live columns with its casts, fillable and hidden flags, relations, events and observers.

open as a page

In Laravel, what does `php artisan stub:publish` do, and how do the published stubs change what `make:*` commands generate?

level: middleimportance: should knowfreq 25%

basics

~10 s

stub:publish copies the framework's common generator templates into a stubs/ folder at the project root. Each make:* command checks that folder before its built-in stub, so edits there shape every class generated afterwards.

open as a page

How should a Laravel console command report progress, results and failure using `table()`, `withProgressBar()`, `fail()` and its return value?

level: middleimportance: should knowfreq 40%

basics

~20 s

A Laravel command prints with info(), warn() and error(), shows rows with table() and long loops with withProgressBar(), and signals failure through its exit code: return self::FAILURE or call fail(). Printing an error alone still exits 0.

open as a page

In Laravel Pint's pint.json, how do you pick a preset, override individual rules and exclude files from formatting?

level: middleimportance: should knowfreq 38%

basics

~20 s

A pint.json in the project root sets "preset" (laravel, per, psr12, symfony or empty), a "rules" object whose entries replace or disable the preset's rules, and "exclude", "notName" or "notPath" to skip folders, name patterns or exact files.

open as a page

How do Laravel Pint's --test, --bail and --repair options differ in what they change and in their exit codes?

level: middleimportance: should knowfreq 35%

basics

~20 s

--test writes nothing and exits 1 if any file would change; --bail does the same but stops at the first offending file; --repair writes the fixes yet still exits 1 when it changed anything. Plain pint fixes and exits 0.

open as a page

In Laravel Sail, how do you switch the app container's PHP version, add a service with `sail:add`, and customise the Dockerfiles with `sail:publish`?

level: middleimportance: should knowfreq 30%

basics

~10 s

PHP is chosen by the laravel.test build context in compose.yaml (vendor/laravel/sail/runtimes/8.x) plus its image name, followed by sail build --no-cache. sail:add appends services; sail:publish copies Sail's Dockerfiles into ./docker for editing.

open as a page

In Laravel, what does the global `--env` option on an Artisan command actually change, and why can `php artisan migrate --env=staging` still hit your local database?

level: seniorimportance: should knowfreq 25%

basics

~20 s

--env sets the environment name the command runs under and, when config is not cached, loads .env.<name> instead of .env if that file exists. Without such a file, or with cached config, the values still come from .env or the cache.

open as a page

What happens when a Laravel controller runs `Artisan::call('invoices:resend-failed', [...])`, and when should you use `Artisan::queue`, `$this->call` or `callSilently` instead?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Artisan::call() runs the command synchronously inside the current request, returns its exit code, buffers its output for Artisan::output() and lets exceptions propagate. Artisan::queue() runs it later on a worker; inside a command, $this->call() and callSilently() run another command.

open as a page

How does implementing `Isolatable` on a Laravel command prevent overlapping runs, and what should `isolatableId()` return for a per-customer invoice re-send command?

level: seniorimportance: should knowfreq 35%

basics

~20 s

Implementing Isolatable adds an --isolated option; with it, Laravel takes an atomic cache lock named after the command before handle() runs and skips the run if the lock is held. isolatableId() should return the customer ID so different customers can run at once.

open as a page

A Laravel command asks `confirm('Re-send 40 invoice emails?')` through Laravel Prompts; what happens when it runs from cron or with `--no-interaction`, and how should you design it?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Without an interactive terminal, Laravel Prompts does not ask: each prompt returns its default after validating it. confirm() defaults to true, so an unattended run answers yes; a required prompt with no usable default throws NonInteractiveValidationException.

open as a page

A Laravel pull request is drowning in formatting noise because Pint reformatted files nobody touched; how would you use --dirty, --diff and a pre-commit hook to stop it?

level: seniorimportance: should knowfreq 28%

basics

~20 s

Land one formatting-only commit that runs Pint over the whole app, then scope every later run: --dirty locally or in a pre-commit hook, --diff=origin/main --test in CI, with one committed pint.json and a locked Pint version.

open as a page

Why is Laravel Sail meant for local development rather than production, and how would you choose between Sail, Herd and a custom Docker setup for a team?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Sail's image is a development box: artisan serve runs PHP's built-in development server, Xdebug and build tools are installed, code is bind-mounted and credentials are throwaway. Pick Sail for repo-pinned setups, Herd for native speed, custom Docker for production parity.

open as a page