Development
Lazydev Mode
Understand the development-only build tag and control-plane endpoints 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 /buildinfo
GET /dependencies
GET /dependencies/shutdown
POST /dependencies/shutdown
GET /dependencies/shutdown/events
GET /cache
GET /cache/entry
POST /cache/on
POST /cache/off
GET /jobs
POST /views
POST /_golazy/views/reload
POST /_golazy/open-editor
GET /routes returns the registered route table. GET /buildinfo returns the
running app's Go module build information from runtime/debug.ReadBuildInfo,
including Go version, command path, main module, dependencies, replacements,
and build settings such as VCS metadata when the toolchain recorded them.
GET /dependencies returns the lazydeps application service graph with the
app root, service nodes, and directed dependency edges. The shutdown
endpoints expose a lazydev-only simulation: POST /dependencies/shutdown can
delay for test traffic, mark /readyz not ready, report active requests and
connections, wait for active requests to finish, and cancel services while
GET /dependencies/shutdown/events streams each state change.
GET /cache returns cache
enabled state, stats, keys, and inspectable entry metadata exposed for
development inspection. GET /cache/entry?key=... returns a selected entry
body when the backend supports inspection. POST /cache/on and
POST /cache/off toggle the app cache. GET /jobs
returns lazyjobs definitions, counts, and recent job state. 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 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 does not force OTEL exporters into the child app. Lazydev builds install
request telemetry unless OTEL_SDK_DISABLED=true is present, but detailed
request monitoring is off by default. Enable it from the development panel to
write local files:
.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 request-level allocation counts, memory deltas, system
memory, stack, GC counters, and lazydev-only per-region allocation samples. 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.
The Requests tab reads the app control plane's /requests/traces snapshot,
which is built from the .spans and .log.json sidecars. Its search is
server-side path filtering through the q query parameter, and its type filter
uses type=framework, type=assets, type=other, or all requests. Request
type is derived from the last traced middleware that handled the request
without calling the next handler. The tab shows recent captured request paths,
then opens request detail tabs for Headers, Tracing, and Logs. The Tracing tab
starts with a request status strip, then a backend-sorted region table and a
flamegraph. Turn on Include golazy to include middleware, router, dispatch, and
other framework regions. Table headers sort by total or self time, allocation
count, and memory bytes; the flamegraph scale follows the selected metric.
Flamegraph bars use square classical flamegraph colors, show only the span name
inside the bar, and keep full timing and allocation details in the browser
tooltip. The region metrics table above the flamegraph keeps compact rows
without reducing text size. The flamegraph pane grows to the graph's full
height; once the table is at its minimum height, long graphs make the request
detail area scroll for inspection instead of clipping inside the flamegraph
pane.
When the sidecar includes lazydev allocation samples, those region allocation
values are process-wide runtime.ReadMemStats deltas sampled when spans start
and end, so they are development estimates rather than exact runtime.mallocgc
attribution.
Those request spans include framework child regions for middleware, routing, dispatch, controller setup, action calls, view rendering, layouts, and partials. Region names include concrete middleware, controller/action, template, and partial identifiers for Go runtime trace inspection.
Read Development Panel for the panel UI and Control Plane for production control-plane configuration.