Debugging
Finch includes a built-in browser debugging bar for local development. When enabled, a collapsible panel appears at the bottom of every rendered page, giving you real-time insight into the current request without leaving the browser.
The debug bar shows:
- Registered routes and which one matched the current request
- Request details (method, path, headers, session, cookies)
- Template parameters passed to the current view
- Server logs and errors for the current request
- Buttons to reload the page or restart the server
Enabling the Debugger
Two conditions must both be true for the debugger to activate:
enableLocalDebugger: trueinFinchConfigs— this allows the debugger to run at all.isLocalDebugreturnstrue— this indicates the app is currently running in development mode.
isLocalDebug is computed automatically:
- If the environment variable
LOCAL_DEBUGis set, it uses that value (true/false). - Otherwise it checks
Console.isDebug, which istruewhen the app is run withdart run(not compiled withdart compile exe).
In app.dart:
FinchConfigs configs = FinchConfigs(
// Allow the debugger to be shown when running in debug mode
enableLocalDebugger: env.getBool('ENABLE_LOCAL_DEBUGGER', false),
);
In your .env file (development):
ENABLE_LOCAL_DEBUGGER=true
LOCAL_DEBUG=true
In production, both should be false (or simply omit them, as the defaults are false).
How It Works
When enableLocalDebugger && isLocalDebug, Finch:
- Injects debug data into every
renderView()response. - Appends the debug bar HTML at the bottom of the page.
- Exposes a WebSocket-based live-reload endpoint.
The debug bar is never injected when:
enableLocalDebuggerisfalseisLocalDebugisfalse- The response is JSON (
renderData()) or plain text (renderString())
Checking Debug Mode in Code
You can read isLocalDebug in your controller or template to conditionally show development-only content:
// In a controller
if (FinchApp.config.isLocalDebug) {
Console.p('Debug: current user is ${rq.getSession("user")}');
}
<!-- In a template -->
{% if isLocalDebug %}
<p class="debug-note">Running in debug mode</p>
{% endif %}
isLocalDebug is automatically injected as a template variable for every renderView() call, so no rq.addParam() is needed.
Terminal Panel
When the app is started with finch serve (not a plain dart run), the CLI opens a WebSocket server on --terminalPort (default 8282) that streams the running process's stdout/stderr. The debug bar's Terminal tab connects to this port automatically, so you can watch server logs and console output without switching to the terminal window, and send commands back to the running process from the browser.
# Use a custom terminal port
finch serve --terminalPort 9000
This only works through finch serve, since that's the process that spawns the app and wires FINCH_TERMINAL_PORT into its environment. Running the app directly with dart run leaves the Terminal tab disconnected.
DartDevTools Panel
finch serve also starts the app with --enable-vm-service=8181/0.0.0.0 --disable-service-auth-codes, binding the Dart VM service to all interfaces (not just localhost) so it stays reachable from inside a Docker container. The debug bar embeds a DevTools tab that connects to this VM service on port 8181, giving you memory, performance and logging views for the running app directly in the browser.
If you're running Finch in Docker, make sure ports 8181 and 8282 are published alongside the app port — see Docker for Finch.
Error Pages
In debug mode, error pages (e.g., 404, 500) include a full stack trace to help diagnose the issue. In production mode, error pages show only a user-friendly message without internal details.