Debugging visibility in production is hard. Telescope gives you that visibility locally, capturing every request, database query, queued job, and mail message before you ship to staging or production. We've found it catches integration bugs that unit tests miss.
Laravel Telescope: PHP & Laravel lessons from production is about bringing production-grade observability into your development environment. When a customer reports that their bulk order took 45 seconds to process, you need to know exactly which queries ran, how long each took, and whether a job queued properly. Telescope shows you all of that in a beautiful dashboard, running locally on your machine.
The challenge most teams face is that their local development environment doesn't mirror production closely enough. You might test a feature on your laptop with a small dataset, ship it, and then discover it times out with 100,000 records. Telescope closes that gap by letting you instrument your code heavily during development, capture detailed traces, and identify bottlenecks before deployment.
See every request with queries
Telescope's core value is showing you exactly what happens during each HTTP request. Every query, every external call, every variable assigned—it's all there in the timeline view.
Install Telescope first:
composer require laravel/telescope --dev
php artisan telescope:install
php artisan migrateStart your dev server and navigate to /telescope. You'll see a list of requests. Click into one:
| Request | GET /orders/1234 |
| Duration | 487 ms |
| Status | 200 |
| Queries | 18 |
Now expand the queries tab. You see all 18 SQL statements in order, with execution time for each. This is where the real insight lives. A junior developer might see "18 queries, so what?" A production team knows this is an N+1 problem waiting to happen.
Real example: you load an order with 100 line items. Without optimization, you query the order once, then loop and query the customer, shipping address, and product details for each line. That's 1 + (3 × 100) = 301 queries. With Telescope, you see it immediately:
// Bad: loads customer for each line item
$order = Order::find(1234);
foreach ($order->lineItems as $item) {
$customer = $item->order->customer; // Query per item
}Telescope shows you 301 queries. You refactor with eager loading:
$order = Order::with('lineItems.order.customer')->find(1234);
foreach ($order->lineItems as $item) {
$customer = $item->order->customer; // No query, already loaded
}Now Telescope shows 2 queries total. The dashboard proves the fix works before you ever commit.
Telescope also captures request headers, response status, middleware timing, and exceptions. If a request throws an error, you see the stack trace right there. No need to dig through logs; the full context is in the timeline.
Inspect queued jobs and mail
Jobs and mail are often where production surprises hide. A job might work fine with 10 items in the queue but fail with 1,000. Mail might be silently failing because of a misconfigured SMTP server.
Telescope captures all of this. When you dispatch a job:
ProcessOrder::dispatch($order);Telescope logs it in the "Queues" tab. You see:
- Job class name
- Queue name and connection
- Arguments passed
- Execution time (if run synchronously)
- Any exceptions thrown
Same for mail. When you send an email:
Mail::to($user)->send(new OrderConfirmation($order));Telescope logs it under "Mail". You can inspect the rendered HTML, see headers, check attachments, and verify the to/from/cc addresses before sending to a real mailbox.
This is invaluable for debugging notification systems. Say you're building a feature that sends different emails based on customer tier. In development, you can send to fake addresses, check Telescope, and verify the logic branches correctly without spamming anyone.
For jobs, Telescope by default runs them synchronously in development (via QUEUE_DRIVER=sync). This means you see immediate feedback. If a job fails, Telescope shows the exception. If it succeeds, you see execution time and memory usage. This catches bugs that would only appear in production with an async queue.
You can also test with a real async driver locally by setting QUEUE_DRIVER=redis and running a queue worker in another terminal. Telescope still captures everything.
Find slow queries
Telescope includes a "Queries" dashboard that ranks all queries by execution time. This is your performance debugging tool.
Open the Queries tab and sort by duration. You might find:
- A SELECT * on a large table with no index
- A complex JOIN that could be denormalized
- A subquery that should be a separate statement
- Missing WHERE clauses filtering millions of rows
Real scenario: your reporting page loads slowly. Telescope shows a query that scans 2 million rows just to count distinct customers. The query is:
SELECT COUNT(DISTINCT customer_id) FROM orders WHERE created_at > NOW() - INTERVAL '30 days';Without an index on created_at, this is slow. You add the index:
// In your migration:
Schema::table('orders', function (Blueprint $table) {
$table->index('created_at');
});Run the page again in Telescope. The query now completes in 50ms instead of 8 seconds. You've proven the fix works locally before deploying.
Telescope also has a slider to hide fast queries. Set it to 100ms and you only see queries taking longer than 100ms. This helps focus on real problems.
Note: in production, you shouldn't run Telescope because it logs everything to your database, which is overhead. But in a staging environment that mirrors production data, you can enable it temporarily to profile under realistic conditions.
Disable or restrict in production
Telescope writes every request, query, job, and mail to your database. For a busy application, this is thousands of records per hour. Your telescope table grows fast and queries get slow.
By default, Telescope only runs in local and testing environments. Check config/telescope.php:
'enabled' => env('APP_ENV') === 'local',Never enable Telescope in production. The overhead isn't worth the benefit; you have APM tools like DataDog or New Relic for that.
In staging, you might want it temporarily. Enable it with caution:
// Prune old records aggressively
'prune' => [
'enabled' => true,
'hours' => 1, // Delete entries older than 1 hour
],
// Sample requests to reduce volume
'recorders' => [
Recorders\RequestRecorder::class => [
'sample_rate' => 0.1, // Capture 10% of requests
],
],Better yet, use a feature flag or environment variable to enable Telescope only for specific IP addresses:
// In a middleware:
public function handle($request, Closure $next)
{
if (!in_array($request->ip(), config('telescope.allowed_ips', []))) {
if (config('app.env') !== 'local') {
// Disable Telescope for this request
Telescope::stop();
}
}
return $next($request);
}This lets you use Telescope in staging without it capturing requests from automated tests or load generators.
Common mistakes
- Forgetting to prune Telescope data: The telescope table grows unbounded if you don't set a prune schedule. Set `'prune' => ['enabled' => true, 'hours' => 48]` to auto-delete old entries.
- Leaving Telescope enabled in production: It's disabled by default, but don't accidentally enable it. The performance hit and disk usage will surprise you.
- Trusting Telescope timings alone: Telescope measures PHP execution time, not network latency or database server time. A 100ms query in Telescope might be a slow I/O operation on the database server itself. Always cross-check with database-level profiling tools.
- Not using eager loading insights: Telescope shows N+1 queries clearly, but you have to act on them. Make it a code review habit: "Did we check Telescope for this feature?"
- Ignoring slow migrations and seeders: Enable Telescope when running migrations or seeders locally. You'll catch slow bulk operations before they hit production.
Key takeaways
- Telescope shows every request, query, job, and mail in your dev environment, catching integration bugs that unit tests miss.
- The queries dashboard ranks SQL by execution time, helping you spot N+1 problems and missing indexes before deployment.
- Use Telescope to verify job dispatching and mail rendering work correctly, without hitting real services.
- Disable Telescope in production; enable it only in local or staging with appropriate sampling and pruning.
- Make inspecting Telescope output part of your code review process for performance-sensitive features.






Comments
Loading comments…