Development
Lazydev Mode
Understand the development-only build tag, control-plane endpoints, and panel runtime used by lazy.
What lazydev means
The default lazy development command builds your app with the lazydev build
tag. That tag enables local-only behavior such as disk-backed views, logical
asset paths, detailed error pages, editor opening from error frames, route
inspection, and view-cache reloads.
Production builds do not include lazydev handlers.
Development control plane
When lazy starts the app, it also passes CONTROL_PLANE_ADDR so the app can
serve development endpoints on an internal control-plane address:
GET /routes
GET /cache
POST /cache/on
POST /cache/off
POST /views
POST /_golazy/views/reload
POST /_golazy/open-editor
GET /routes returns the registered route table. GET /cache returns cache
enabled state, stats, and any backend keys exposed for development inspection.
POST /cache/on and POST /cache/off toggle the app cache. POST /views
reloads disk-backed views without rebuilding or restarting the app. The
/_golazy/views/reload route remains as a compatibility alias.
Detailed error pages call POST /_golazy/open-editor when you click a frame.
The request includes an absolute file path and line number, and GoLazy starts
$EDITOR without waiting.
Development panel
The public development address serves the panel under /_golazy/ and proxies
normal app traffic to the running app process. The panel remains available
while the app is building, failed to compile, running, or crashed.
The panel JavaScript is served as a normal external asset. GoLazy does not
inline development-panel JavaScript into app HTML. Proxied app pages receive a
fixed bottom GoLazy development panel iframe that loads /_golazy/. The
client reserves the same height as bottom padding on the html element and
marks the panel host with data-turbo-permanent so Turbo navigation does not
remove it. The panel proxies cache inspection and cache on/off requests to the
app control plane so browser requests stay on the public development origin.
The served panel uses a DevTools-style shell with compact tabs, toolbar rows, dense status panes, and a bottom status bar. Existing lazy behavior is available inside that shell: App Logs shows build/run state, latest output, lifecycle events, and changed files; Actions provides rebuild, restart, open-app, and view-cache controls. Requests, Console, Traces, Routes, and Assets are present as disabled or empty states until their APIs are wired.
Development request traces
The lazy development proxy assigns request correlation before forwarding app
traffic. It preserves safe incoming X-Request-ID and valid W3C traceparent
headers, or generates both when they are missing. The app telemetry middleware
uses those headers for its request id, request span, logs, metrics labels, and
the response X-Request-ID.
lazy starts the child app with OTEL trace and log exporters set to otlp and
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf. In this first implementation there
is no OTLP receiver; lazydev builds write local files instead:
.tmp/traces/<request-id>.trace
.tmp/traces/<request-id>.spans
.tmp/traces/<request-id>.log.json
The .trace file is a Go runtime trace. The .spans file is JSON with request
and span metadata plus allocation counts, memory deltas, system memory, stack,
and GC counters. The .log.json file is JSONL for request-local logs emitted
through lazytelemetry or lazylogs. Runtime tracing is process-wide, so
lazydev serializes traced requests while each .trace file is recorded.
Chrome DevTools extension
The chrome-extension directory contains an unpacked Chrome extension for the
development panel. It adds a GoLazy icon to the Chrome extension bar and a
GoLazy panel in Chrome DevTools.
The current extension is UI-only. Its requests, console, app logs, and traces views use static data and do not connect to the GoLazy development backend yet. The request view uses a Network-style toolbar with record and disable-cache controls, type filters, App/Assets/All scope filters that default to App, a compact request list, and detail tabs for headers, preview, response, initiator, timing, params, rendering, database, cache, logs, tracing, and request-scoped actions. Chrome-like dark and light surfaces use the default DevTools theme colors. The panel must fit inside the DevTools viewport; table columns should collapse or truncate instead of pushing the extension wider than the available panel space.
Chrome does not expose DevTools' private stylesheet to extension panels. The extension vendors a small adapted subset of DevTools token and class names, keeps the Chromium BSD-style license beside that CSS, and switches light/dark values through the public DevTools theme API.
The future request feed should start with Chrome's DevTools extension network
API: seed from chrome.devtools.network.getHAR(), listen to
chrome.devtools.network.onRequestFinished, and call a request's getContent()
only when response or preview content is needed. Lower-level
chrome.debugger/Chrome DevTools Protocol access should stay out of the default
extension path unless a later feature needs data the DevTools network API cannot
provide.
Read Run With lazy for the everyday workflow and Control Plane for production control-plane configuration.