You’re debugging a slow page. You have a vague suspicion something in the authentication layer is firing too many database queries, but profiling it manually means adding debug output everywhere, clearing it out, and repeating. Laravel Telescope solves this elegantly: it quietly records everything that happens in your application – every request, every query, every job, every cache hit – and makes it browsable in a clean dashboard.
What Telescope Captures
- HTTP requests (headers, session, response status, duration)
- Exceptions (with full stack traces)
- Log entries
- Database queries (with bindings and execution time)
- Queued jobs (status, payload, result)
- Scheduled tasks (output, execution time)
- Mail and notifications
- Cache operations (hits, misses, writes)
- Variable dumps (
dump()output appears in Telescope) - Model events (creating, updating, deleting)
Installation
# Install as a dev dependency
composer require laravel/telescope --dev
# Publish assets and migrations
php artisan telescope:install
# Run migrations
php artisan migrate
# Access the dashboard
# http://your-app.test/telescope
Local-Only Registration (Important)
The default installation registers Telescope for all environments – a security and performance problem. Fix this:
# In composer.json - prevent auto-discovery
{
"extra": {
"laravel": {
"dont-discover": ["laravel/telescope"]
}
}
}
// In app/Providers/AppServiceProvider.php
public function register(): void
{
if ($this->app->environment('local')) {
$this->app->register(LaravelTelescopeTelescopeServiceProvider::class);
$this->app->register(TelescopeServiceProvider::class);
}
}
Dashboard Navigation
Visit /telescope locally. The most useful views:
- Requests – every HTTP request with duration, memory, session, authenticated user, and every database query that fired with individual timings
- Queries – all SQL queries sorted by slowest first – the fastest way to spot N+1 problems
- Jobs – queue jobs with payload, attempt count, and failure exceptions
- Exceptions – full stack trace with the request that triggered it
Configuring Watchers
// config/telescope.php
'watchers' => [
WatchersQueryWatcher::class => [
'enabled' => env('TELESCOPE_QUERY_WATCHER', true),
'slow' => 100, // Highlight queries over 100ms
],
WatchersRequestWatcher::class => [
'enabled' => env('TELESCOPE_REQUEST_WATCHER', true),
'size_limit' => env('TELESCOPE_RESPONSE_SIZE_LIMIT', 64),
],
WatchersExceptionWatcher::class => [
'enabled' => env('TELESCOPE_EXCEPTION_WATCHER', true),
'ignore' => [
SymfonyComponentHttpKernelExceptionNotFoundHttpException::class,
],
],
// Disable watchers you don't need
WatchersCacheWatcher::class => [
'enabled' => false,
],
],
Filtering Entries
// app/Providers/TelescopeServiceProvider.php
Telescope::filter(function (IncomingEntry $entry) {
if ($entry->isClientRequest()) {
return true;
}
if ($entry->type === EntryType::QUERY && $entry->content['slow']) {
return true;
}
return $entry->isReportableException() ||
$entry->isFailedJob() ||
$entry->hasMonitoredTag();
});
Pruning: Keep the Database Clean
// routes/console.php
Schedule::command('telescope:prune')->daily();
// Keep entries for 48 hours
Schedule::command('telescope:prune --hours=48')->daily();
// Run manually
php artisan telescope:prune
Spotting N+1 Query Problems
Load a page that lists users, then check Telescope → Requests. If you see the same query repeated with different IDs:
// What you see in Telescope:
// SELECT * FROM posts WHERE user_id = 1 0.2ms
// SELECT * FROM posts WHERE user_id = 2 0.2ms
// ...repeated 47 more times
// Fix - add eager loading
$users = User::with('posts')->get();
// Now Telescope shows one query:
// SELECT * FROM posts WHERE user_id IN (1,2,3...) 0.8ms
Using Tags
// Tag requests for custom filtering
Telescope::tag(function (IncomingEntry $entry) {
return $entry->type === EntryType::REQUEST
? ['status:' . $entry->content['response_status']]
: [];
});
Conclusion
Telescope changes debugging from guesswork to evidence. The combination of request-scoped query tracing, exception context preservation, and job monitoring removes the need to pepper code with Log::info() calls. Install it as a dev dependency on every Laravel project and leave it running – the N+1 queries it exposes will often save you more time than the installation takes.

Leave a Reply
You must be logged in to post a comment.