Laravel Nightwatch: what it is, why use it, and the multi-project gotcha
If you’ve been running Laravel apps in production without proper monitoring, you’re flying blind. Logs only tell you what you thought to log, and by the time a user reports a problem, the context is usually gone. Laravel Nightwatch is Laravel’s first-party answer to this — and it’s worth knowing about before you reach for Datadog, Sentry, or New Relic again. There’s also one setup catch I hit immediately when running it across multiple local projects, which I’ll cover at the end so you don’t waste 20 minutes on it like I did.
What is Laravel Nightwatch
Nightwatch is the official application monitoring platform built by the Laravel team, announced at Laracon EU 2025. It’s a hosted SaaS — your app installs the open-source laravel/nightwatch package, an agent runs locally and forwards events to Nightwatch’s servers, and you get a dashboard showing what your application is actually doing in real time.
It tracks the things you’d expect from an APM — requests, exceptions, slow queries — but because it’s purpose-built for Laravel, it also understands jobs, scheduled tasks, notifications, mail, events, and the relationships between them. When a queued job fails, you can trace it back to the request that dispatched it. When a route is slow, you can see exactly which queries and outgoing HTTP calls contributed to the time.
Nightwatch vs Telescope vs Pulse
Laravel now has three observability tools, and they’re not interchangeable:
| Tool | Purpose | Where it runs |
|---|---|---|
| Telescope | Granular local debugger. Shows every request, query, job, mail. | Local dev only — never production |
| Pulse | Lightweight aggregated metrics dashboard. CPU, queue throughput, slow queries. | Self-hosted, fine in production |
| Nightwatch | Full production APM with event-level detail and team collaboration. | Hosted SaaS, agent runs alongside your app |
Telescope is for “what just happened on my machine?” Pulse is for “what’s the overall health of my app right now?” Nightwatch is for “what’s happening in production, across requests, jobs, and time, and how do we fix it as a team?”
Why use it
A few reasons it’s worth a look, especially if you’re already in the Laravel ecosystem:
- It speaks Laravel natively. No translation layer between your app’s concepts and the dashboard. Routes are routes, jobs are jobs, scheduled tasks are scheduled tasks. You don’t have to mentally map Laravel’s lifecycle onto a generic APM’s vocabulary.
- Setup is genuinely close to one command. Install the package, set your token, run the agent. No instrumentation code to scatter through your app, no manual span creation. The framework integration does the heavy lifting.
- Connected events. A request, the queries it ran, the jobs it dispatched, the mail it sent — all linked in one view. Tracking down “this slow request also caused that failed job” stops being detective work.
- Issue grouping. Exceptions get grouped automatically, so a single bug hitting a thousand users doesn’t drown your inbox in a thousand notifications.
- Free tier to start. Pricing is event-based with sampling controls, so you can get value without committing to anything. For high-traffic apps, sampling lets you keep cost predictable.
The honest caveat: it’s still a relatively new product. If your app is already wired into Sentry for errors and Datadog for metrics, Nightwatch isn’t going to magically replace both on day one. But for new projects, or for Laravel shops that want monitoring built by people who actually use Laravel, it’s a strong default.
The gotcha — port conflicts on multi-project setups
Now the practical bit. The Nightwatch agent is a long-running process that listens locally on a TCP port. Your app pushes events to that port, the agent batches them, and forwards them on to the Nightwatch ingest API.
By default, that port is 2407. The standard install instructions assume one project per machine, so both the agent and the app fall back to 127.0.0.1:2407 with no configuration needed. That’s fine — until you try to run the agent for a second project on the same machine. It won’t start. The port is already taken.
I hit this on my local dev box the first time I tried to monitor two Laravel apps side by side. The fix is straightforward once you know it, but the default setup walkthrough doesn’t mention it, so it’s worth flagging.
The fix
Two things need to match up for every project:
- The agent must be started with
--listen-on=127.0.0.1:<port>. - The Laravel app’s
.envmust setNIGHTWATCH_INGEST_URI=127.0.0.1:<port>to the same value.
If those two values drift out of sync, the agent boots, the app thinks everything is fine, and no events make it through. Silent failure, hardest kind to debug.
Project 1 — default port:
# /var/www/project-1/.env
NIGHTWATCH_INGEST_URI=127.0.0.1:2407
cd /var/www/project-1
php artisan nightwatch:agent --listen-on=127.0.0.1:2407
Note: Setting the env var explicitly for project 1 isn’t strictly required (2407 is the default), but I do it anyway so both projects look the same and there’s no “magic” default to remember six months from now.
Project 2 — bump it to 2408:
# /var/www/project-2/.env
NIGHTWATCH_INGEST_URI=127.0.0.1:2408
cd /var/www/project-2
php artisan nightwatch:agent --listen-on=127.0.0.1:2408
Third project, 2409. Fourth, 2410. The port number itself doesn’t matter — pick anything free, just keep it unique per agent and matched to the env var.
Verifying
Hit a route in each app, then check the Nightwatch dashboard. Events should appear under the correct environment for each project. If they don’t:
php artisan nightwatch:status
Run that from inside the project — it’ll tell you whether the app can actually reach its agent. The most common cause of silent failure is the env var and --listen-on value drifting after a copy-paste.
Also: if you’ve ever run config:cache, Laravel won’t pick up your .env change until you clear it:
php artisan config:clear
Keeping agents running
Foreground terminals are fine while you’re testing. For anything ongoing — including local dev you want monitored throughout the day — use a process supervisor. Supervisor or systemd on Linux. launchd on macOS, or tmux/screen if you don’t need them across reboots. Each agent gets its own supervisor program block, same pattern as Laravel queue workers, pointed at the right project and listen port.
Note: Laravel Forge handles this multi-site scenario automatically through its official Nightwatch integration. The manual setup above is for self-managed servers, local dev, and homelab boxes — anywhere you’re wiring it up yourself.
Quick reference
# Project 1 (default port)
# .env
NIGHTWATCH_INGEST_URI=127.0.0.1:2407
php artisan nightwatch:agent --listen-on=127.0.0.1:2407
# Project 2 (custom port)
# .env
NIGHTWATCH_INGEST_URI=127.0.0.1:2408
php artisan nightwatch:agent --listen-on=127.0.0.1:2408
# Health check (run from inside each project)
php artisan nightwatch:status
# After any .env change
php artisan config:clear
Originally posted on noukeosombath.com.