Why does Laravel Telescope's telescope_entries table grow so quickly, and how do telescope:prune and Telescope::tag() keep recorded data bounded and findable?
answer
- one row per entry, many per request
- --hours=24 by default
- --keep-exceptions keeps exception rows
- tag closure merges with automatic tags
- Auth:id and Model:key tags
basics
~20 sEvery request can write dozens of entries (queries, models, events, cache calls), so the table grows fast. telescope:prune deletes entries older than --hours (24 by default), optionally keeping exceptions; Telescope::tag() adds your own searchable tags beside the automatic ones.
solid answer
~40 sTelescope writes one row per **entry**, and a single admin page can produce a request, dozens of queries, model events, cache hits and log lines, so `telescope_entries` and `telescope_entries_tags` grow quickly. `php artisan telescope:prune` deletes entries older than `--hours` (default 24) in chunks; `--keep-exceptions` keeps exception entries. The docs recommend running it daily, for example with `--hours=48`. `telescope:clear` empties everything, and `telescope:pause` stops recording without a deploy. To make what remains findable, Telescope tags entries automatically (`Auth:{id}` for the user, `App\Models\Order:15` for models in jobs, events and mail, `slow` for slow queries, `failed` for failed jobs), and `Telescope::tag(fn (IncomingEntry $entry) => [...])` merges your own, such as `status:500` or a tenant id. Tags drive dashboard search and monitored tags.
code
php · 17 lines<?php
use Laravel\Telescope\EntryType;
use Laravel\Telescope\IncomingEntry;
use Laravel\Telescope\Telescope;
// In App\Providers\TelescopeServiceProvider::register()
Telescope::tag(function (IncomingEntry $entry) {
if ($entry->type === EntryType::REQUEST) {
return [
'status:'.$entry->content['response_status'],
'area:'.(str_starts_with($entry->content['uri'], '/admin') ? 'admin' : 'site'),
];
}
return [];
});go deeper
Know that Telescope data grows quickly and that telescope:prune deletes old entries, 24 hours by default.
Explain --hours and --keep-exceptions, the automatic tags, and how Telescope::tag() adds searchable tags.
Set retention and tagging deliberately, use monitored tags to record a single user's activity on shared environments, and keep storage cost in check.
Set data-retention rules for recorded request history across environments, aligned with storage budgets and privacy obligations.
## Why the table grows Telescope stores each recorded item as a row in `telescope_entries`, with tags in `telescope_entries_tags`. The key point is **one row per entry**, not per request. A single request to the admin orders page can create: - one request entry; - one entry per query (often dozens); - model entries for each `eloquent.*` event, plus a hydration count; - event, cache, gate and view entries; - log entries at or above the log watcher's level. Multiply that by every request, command, job and scheduled task and the table grows by thousands of rows per hour even on a quiet local machine. Large tables slow the dashboard itself and every insert Telescope makes. ## telescope:prune ```bash php artisan telescope:prune # older than 24 hours php artisan telescope:prune --hours=48 # keep two days php artisan telescope:prune --keep-exceptions ``` - `--hours` (default **24**) sets the retention window; entries with `created_at` older than that are deleted. - `--keep-exceptions` skips entries whose type is `exception`, so a week-old error survives while its surrounding queries are removed. - Deletion runs in chunks of the configured `storage.database.chunk` size (1000), so it does not hold one huge delete. The docs recommend running it **daily** through the scheduler. Related commands: 1. `telescope:clear` deletes all entries at once, useful before reproducing a bug. 2. `telescope:pause` sets a cache flag that stops recording; `telescope:resume` removes it. ## Tags: automatic and custom A **tag** is a string attached to an entry and indexed in `telescope_entries_tags`. Telescope adds several on its own: | Tag | Added by | |---|---| | `Auth:{id}` | any entry recorded while a user is authenticated | | `App\Models\Order:15` | jobs, events, mail and notifications that carry models | | `slow` | queries at or above the query watcher's `slow` threshold | | `failed` | jobs that failed | `Telescope::tag()` registers a closure that receives each `IncomingEntry` and returns extra tags, which are **merged** with the automatic ones: ```php Telescope::tag(fn (IncomingEntry $entry) => $entry->type === EntryType::REQUEST ? ['status:'.$entry->content['response_status']] : []); ``` Jobs can also define a `tags()` method, which Telescope uses instead of extracting model tags from the job. ## Using tags to find things - The dashboard's tag search on any screen narrows entries, for example `status:500` on requests or `slow` on queries. - The **Monitoring** screen stores tags in `telescope_monitoring`; entries carrying a monitored tag pass the published filter's `hasMonitoredTag()` check, so on a non-local environment you can temporarily record everything for `Auth:42` while debugging that user's problem, then stop monitoring it. ## A rough sense of scale The growth is easy to underestimate. As an illustration, a page that produces 30 entries, served 10 times a second, adds 300 rows per second, about 26 million rows a day, before counting tag rows. Even at one request a second locally, a busy development day produces tens of thousands of rows. That is why pruning belongs in the setup from day one, not after the dashboard becomes slow. ## A sensible routine 1. Schedule `telescope:prune` daily with a retention you actually use. 2. Add `--keep-exceptions` if exceptions are what you revisit. 3. Tag entries with the identifiers you search by: tenant, order, status. 4. Monitor tags for a short time only, since they widen what is recorded.
- You want to keep a week of exceptions but only a day of everything else. How?Run `telescope:prune --hours=24 --keep-exceptions` daily, which deletes all non-exception entries older than a day but leaves exception entries. Then run a second, less frequent `telescope:prune --hours=168` to remove exceptions older than a week, since `--keep-exceptions` alone never deletes them.
- On staging, how do you capture every entry for one user's session without recording everyone?Add the tag `Auth:{id}` for that user on Telescope's Monitoring screen. The published filter keeps any entry for which `hasMonitoredTag()` is true, so that user's requests, queries and jobs are recorded in full while others are not. Remove the tag when you are done.
saying these in an interview costs you the question
- Telescope writes one row per request, so the table stays small.
- telescope:prune keeps seven days of data by default.
- Telescope prunes old entries automatically without any command.
- Telescope::tag() replaces the automatic tags on an entry.
- --keep-exceptions keeps the queries and logs around each exception too.