skip to content

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%

answer

  1. read-only, from the live connection
  2. db:show: platform, tables, sizes
  3. --counts and --views are slow
  4. db:table: columns, indexes, foreign keys
  5. model:show: casts, fillable, relations, observers

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.

solid answer

~50 s

I start broad and narrow down. `php artisan db:show` prints the connection's engine, server version and open connections and lists every table with its size; `--counts` adds row counts and `--views` the views, both slow on large databases, and `--database=` picks another connection. `php artisan db:table orders` shows one table's columns with types, nullability and defaults, plus its indexes and foreign keys; without a name it lets me search for a table. Then `php artisan model:show Order` joins the live columns with what the model declares — which attributes are fillable, hidden, cast and to what, accessor-backed virtual attributes — and lists its relations, dispatched events, observers and policy. All three read from the live connection and change nothing, and all accept `--json`. What the code says and what the database holds often disagree in legacy apps, and these commands show both.

go deeper

for a junior

Recall what each command prints: db:show for the whole database, db:table for one table, model:show for one model and its table.

for a middle

Explain that model:show merges live columns with the model's casts, fillable and hidden rules, and why --counts and --views can be slow.

for a senior

Use the commands to find drift between models and schema in a legacy app, and know when db:monitor with a DatabaseBusy listener is worth scheduling.

for a principal

Treat schema-versus-model drift as technical debt to measure, and decide how inspection output feeds onboarding docs or automated checks.

## Why start with the data layer In an unfamiliar Laravel application the database is usually the most honest documentation. Migrations may have been squashed, edited or bypassed; models may declare casts for columns that no longer exist. Laravel ships three **read-only inspection commands** that answer the first questions quickly — what is in the database, what does one table look like, and how does a model map onto it — without opening a database client or reading every migration. All three connect through the application's own configuration and accept `--json` for saving or diffing the output. ## `db:show`: the database at a glance `php artisan db:show` reports on the default connection: - the platform: driver name, connection name, server version and number of open connections; - every table with its size, and its schema where the engine has schemas; - `--counts` adds per-table row counts and `--views` lists views — both flagged as slow on large databases, so think before running them against production; - `--types` lists user-defined types (useful on PostgreSQL); - `--database=reporting` inspects another configured connection. A long list of tables with no matching models, or tables named `*_old` and `*_backup`, tells you a lot about the application's history in seconds. ## `db:table`: one table in detail `php artisan db:table orders` prints the table's columns with type, nullability, default and auto-increment flag, then its **indexes** and **foreign keys**. Run without a table name, it offers a searchable list of tables. This is where you check the things migrations do not always show: whether the column the code filters on is actually indexed, whether foreign keys exist or the relations are enforced only in PHP, which columns are nullable. ## `model:show`: the model against the table `php artisan model:show Order` inspects an Eloquent model *and* its live table: | Part of the output | Where it comes from | |---|---| | class, connection, table name | the model class | | attributes: type, nullable, default, unique | the live table's columns and indexes | | fillable, hidden, cast per attribute | the model's mass-assignment rules, hidden list and casts | | appended/virtual attributes | accessor methods on the model | | relations with type and related model | relation methods on the model | | events and observers | dispatched events and registered observers | | policy, custom collection, builder, resource | the model's attributes and conventions | Two implementation details matter when you read it: 1. It needs a working database connection, because columns come from the live schema; a model whose table is missing will not inspect cleanly. 2. Relations are discovered from methods that take no parameters and either declare a relation return type or contain a call such as `$this->hasMany(` — and the command **invokes** those methods to learn the related model. A relation built through a helper, with no return type, can be missed. ## A day-one routine 1. `php artisan db:show` — size up the schema; note surprising tables. 2. `php artisan db:table <table>` on the three or four tables the business depends on — orders, customers, payments. 3. `php artisan model:show <Model>` for each matching model — compare its casts and fillable list with the real columns. 4. Write down the mismatches: columns the model never mentions, casts for columns that do not exist, missing indexes on foreign keys. ## Monitoring rather than inspecting A fourth command in the same family, `php artisan db:monitor --databases=mysql --max=100`, counts open connections on each named connection and dispatches an `Illuminate\Database\Events\DatabaseBusy` event when a count reaches the threshold. It does nothing alone — it is meant to run every minute with a listener that alerts someone. The count comes from the driver: MySQL, MariaDB, PostgreSQL and SQL Server report one, while SQLite reports none, so the command never alerts on the SQLite default. ## Limits - These commands describe structure, not data quality; they will not find orphaned rows. - On pooled PostgreSQL setups, `db:show` and `db:table` use the direct connection when one is configured. - They read what the configured connection can see: a restricted database user may hide tables.

  • How does `db:monitor` turn a connection count into an alert, and why does it stay silent on SQLite?
    `php artisan db:monitor --databases=mysql,pgsql --max=100` reads each connection's open-connection count and dispatches `DatabaseBusy` when the count reaches `--max`; you schedule it every minute and listen for the event to notify someone. The count comes from a driver-specific query that MySQL, MariaDB, PostgreSQL and SQL Server provide; SQLite has none, so the count is null and never reaches the threshold.
  • `model:show Order` lists a `total` cast, but `db:table orders` has no `total` column. What does that tell you?
    The model declares a cast for a column the table does not have — typically a column dropped or renamed by a migration while the model was never updated, or a cast meant for an accessor-backed value. Reading `total` will return null or rely on an accessor, and writing it will fail. It is exactly the drift these commands are for; fix the model or the migration history.

saying these in an interview costs you the question

  • model:show reads only the model class and works without a database connection.
  • db:show --counts is cheap on any database because counts come from metadata.
  • db:table changes the table if the migrations disagree with it.
  • db:monitor sends alerts by itself without any listener or schedule.
  • model:show finds every relation, even ones built through helpers without return types.