Build And Deploy

Changelog

Release changes covered by the latest GoLazy guides.

By Guillermo Alvarez - Published - Updated

Latest release changes

GoLazy v0.1.19 adds opt-in progressive web app support, a reusable browser worker registry, PWA and worker template helpers, and a PWA development-panel tab. Existing applications do not need source changes unless they opt in to lazyapp.Config.PWA or lazyapp.Config.Workers. The lazy development panel also adds Terminal, Docs, and Media tabs. Terminal is backed by xterm.js and a lazy-owned WebSocket; Docs opens current-project and dependency package documentation plus source without adding app routes; Media lists configured storages, file catalog rows, and media variants with upload, download, remove, and URL actions in lazydev builds.

Framework

  • GoLazy adds first slices of golazy.dev/lazymcp, golazy.dev/lazyauth, golazy.dev/lazyoauth, golazy.dev/lazyjwt, and golazy.dev/lazylimit. Applications can opt in with context-aware lazyapp.Config.Auth, lazyapp.Config.OAuth, and lazyapp.Config.MCP functions. MCP modules can expose tools, resources, prompts, Skills over MCP resources, and MCP Apps ui:// resources rendered from app/views/mcp/<name>/...; UI-enabled tools advertise those resources with the MCP Apps ui/resourceUri metadata key.
  • The latest guides now include an AI section for generated AGENTS.md guidance, generated .skills workflows, authentication and OAuth, MCP server modules, and the future response-generator path.
  • The latest guides are now organized as Development, Lazy App, Routing, Controllers, Views, Assets, Testing, Databases, Extra guides, AI, and Build And Deploy. The Development section adds a dedicated Development Panel guide, the small-app material now introduces What's A Lazy App?, and release verification has moved out of the framework testing overview.
  • GoLazy now permanently redirects GET and HEAD requests from trailing-slash route URLs to the same registered route without trailing slashes, preserving query strings. Unknown paths, public assets, and unsafe methods keep their normal behavior. Read Controller Routes.
  • golazy.dev/lazypwa makes applications installable as progressive web apps, serves generated web app manifests and service workers, emits a small browser client for install/update/offline events, and can sync an opt-in offline cache manifest when the app version changes. Read PWA, Workers And Notifications.
  • golazy.dev/lazyworkers provides a reusable registry for service workers, web workers, shared workers, and future worker-like browser scripts. lazyapp exposes it through Config.Workers, installs worker helpers, and lets lazypwa register its service worker through the same registry.
  • The development panel adds a PWA tab that reads /pwa and /workers from the app lazydev control plane and lists installability, offline-cache, push, and registered worker state.
  • The development panel adds a Terminal tab. It bundles xterm.js and connects /_golazy/terminal/connect to a lazy-owned WebSocket backed by lazytui/pty, so terminal sessions run in the current app root without adding app routes or app control-plane endpoints.
  • The development panel adds a Docs tab at /_golazy/docs. It browses current-project package documentation, lists dependency modules from go list -m -json all, and opens source files relative to the selected module root.
  • The development panel adds a Media tab at /_golazy/media. Apps can expose named lazystorage backends, lazyfiles.Files, and lazymedia.Media through lazyapp.Config; the panel lists storage objects, file catalog rows, and media variants, and can upload, download, remove, and show URLs where the configured services support those operations.
  • lazyfiles.Repository implementations can opt into lazyfiles.Lister, and lazymedia.Repository implementations can opt into lazymedia.VariantLister. The JSONL and PostgreSQL repositories implement both listing contracts for development-panel inspection and app-owned tools.
  • golazy.dev/pg starts the PostgreSQL implementation module for framework backends. The first slice adds shared pgx pool helpers, pgmigrate for golazy.dev/lazymigrate, and pgjobs for durable lazyjobs. PostgreSQL migrations use -- +lazy Up and -- +lazy Down sections. Read PostgreSQL.
  • golazy.dev/pg now includes pg.WithPool and pg.FromContext, so apps can open PostgreSQL inside Dependencies and let jobs or request handlers read the app-owned pool from the dependency-initialized context.
  • golazy.dev/pg adds durable PostgreSQL implementations for the storage services: pgfiles for lazyfiles.Repository, pgmedia for lazymedia.Repository, and pgstorage as a lazystorage object backend that lazyassets.Upload can write to.
  • lazyapp.Config.Migrations can bundle lazymigrate.Databases into the app binary. LAZYAPP_MIGRATE=up applies pending migrations and exits, while LAZYAPP_MIGRATE=auto applies them before jobs and normal startup. During migration mode, a separate CONTROL_PLANE_ADDR starts the real control plane early, serves /livez and a not-ready /readyz, and stays active in auto mode as later handlers are mounted.
  • golazy.dev/lazyassets/assetmigrate adapts the app asset registry and a lazystorage backend into an opt-in lazymigrate.DB for object-storage uploads keyed by build version and asset manifest hash. lazyapp now places the asset registry in migration context with lazyassets.FromContext.
  • lazystorage now has conditional write options IfAbsent and IfETag plus ErrPreconditionFailed; the S3 backend maps them to S3 precondition headers and reports missing reads as fs.ErrNotExist.
  • The lazymigrate.Backend contract now explicitly requires synchronized, atomic migration application so concurrent app instances cannot apply the same step twice or corrupt migration metadata.
  • golazy.dev/pg/pgmigrate now treats stale same-checksum concurrent migration steps as no-ops after acquiring its PostgreSQL advisory lock, while rejecting same-ID migrations with different stored checksums.
  • lazymigrate.DB now uses one Sources list for application and package migrations. Use lazymigrate.FromFS(migrations.FS, "postgres") to adapt an embedded migrations package.
  • lazyfiles and lazymedia keep their append-only JSONL repositories in golazy.dev/lazyfiles/jsonl and golazy.dev/lazymedia/jsonl. The parent packages expose Repository interfaces for concrete backends, while the JSONL packages provide JSONLRepository implementations. Read Media.
  • lazyapp.Config.Dependencies now receives a framework-owned *lazydeps.Scope. Applications initialize services through lazydeps.Service, update the app context through the scope, and let GoLazy record the dependency graph for later lifecycle work. Read Application Startup and Dependencies And Services.
  • lazyapp.Config.SEO now receives the dependency-initialized app context and is normally wired as SEO: SEO with the function defined in init/seo.go. Read SEO And Sitemaps.
  • Sitemap generation is now opt-in. GoLazy does not serve an empty /sitemap.xml by default, and robots.txt only advertises a generated sitemap after lazyapp.Config.Sitemap is configured.
  • golazy.dev/lazyconfig fills application config structs from environment variables with Getenv[T] and MustGetenv[T], default field naming, var, default, required and require tags, trimmed string/numeric/bool values, pointer scalar fields, []string splitting, case-insensitive bool parsing, slice entry loading, and optional Validate() error support.
  • SEO helpers support image alt text, Open Graph image dimensions, secure social image URLs, article:published_time, and complete-title preservation. Read SEO And Sitemaps.
  • golazy.dev/lazytui/progress provides named task progress, captured output, warnings, mise command helpers, and UI takeovers for interactive terminal steps.
  • golazy.dev/lazywebsocket provides an adapted Gorilla WebSocket implementation for framework and local development tooling without adding an external module dependency. Read WebSockets.
  • lazyapp.ListenAndServe now mounts the standard pprof handlers automatically on the control plane when CONTROL_PLANE_ADDR runs on a different listener from the application. Same-listener and manually served control planes still require lazycontrolplane.Config{Pprof: true}.
  • golazy.dev/lazyerrors provides application-owned errors that format like fmt.Errorf, prefix messages with the caller, preserve single and multiple %w wrapping, and expose recorded []lazyerrors.Frame backtraces.
  • golazy.dev/lazytelemetry provides OpenTelemetry-compatible environment config, request-id middleware, context-aware slog logging, OpenTelemetry-backed spans, log-to-span events, OpenTelemetry meter measurements, and in-memory request metrics. lazyapp.New installs telemetry automatically when meaningful OTEL_* environment variables are present, mounts Prometheus text metrics on the control plane when OTEL_METRICS_EXPORTER=prometheus and CONTROL_PLANE_ADDR is set, and includes lazycache stats in that scrape output. Production builds do not expose control-plane metrics on the public app listener when CONTROL_PLANE_ADDR is unset. OTEL_SDK_DISABLED=true disables telemetry. Lazydev builds can also record per-request Go runtime traces, span JSON, and request-local log JSONL under .tmp/traces when detailed request monitoring is enabled from the development panel. Framework request spans now include child regions for middleware, routing, dispatch, controller setup, action calls, view rendering, layouts, and partials. Request ids are attached to request spans, child regions, and log span-events. Read Telemetry.
  • golazy.dev/lazysupport/inflection.Irregular lets applications register domain-specific singular/plural pairs before resource routes derive conventional names. Read REST Resources.
  • The latest telemetry guide now documents the Kubernetes production shape: ingress-nginx OpenTelemetry is enabled per Ingress but collector and sampler settings live on the nginx controller ConfigMap; Prometheus Operator scraping should use PodMonitor resources for the GoLazy control-plane /metrics endpoint.
  • lazyapp now layers application views over framework default views from lazycontroller, so controller errors render a built-in mobile friendly app/error page unless the app provides app/views/app/error.html.tpl. Raw error details plus lazyerrors and panic backtraces are exposed to that view only in development/detail mode. The built-in view shortens frame paths relative to the workspace, current directory, module cache, or module path where possible, and lazydev can open a clicked frame in $EDITOR, using VS Code's -g file:line form or a discovered terminal for terminal editors. New apps can rely on that framework view and add app/views/app/error.html.tpl only when they want a custom error page.
  • lazycontroller.Base now provides SetLater and SetWhenNeeded for request-local deferred view data. They store a Valuer under the template key and let templates call {{.name.Value}} while the controller can still use the returned value directly. Read Template Data And Helpers.
  • Templates can use link_to with path_for, attr, data, and unless_current to render route links without handwritten anchor tags. Read Template Data And Helpers.
  • golazy.dev/lazycache provides the cache contract, typed Get / Set helpers, standardized stats, and On / Off switching. lazyapp installs a default in-memory backend, exposes App.Cache, and registers controller, partial, and Turbo frame body caching helpers. The development panel exposes cache stats, keys, searchable entry metadata, selected entry content, and On/Off actions through the lazydev control plane. Controller and template render cache keys include the app build version, and active render variants when present, to avoid stale bodies across deploys and variant-specific renders. Read Caching.
  • lazycontroller.Base.Layout is the named-layout selection API. The previous SetLayout alias is removed in v0.1.17. CacheKey and CacheKeyF now return true when they wrote an existing cached response, so controller actions should return nil immediately on a cache hit. lazy upgrade --target v0.1.17 rewrites common call shapes automatically. Read Caching and Views And Layouts.
  • golazy.dev/lazyjobs provides a background job runner with typed JSON job payloads, an in-memory backend, retries, app-context injection through lazyapp.Config.Jobs, and read-only job state on the control plane. The development panel now includes a Jobs tab. Read Background Jobs.
  • lazyapp.Config.Jobs now runs after Dependencies with the dependency-initialized app context. Use lazyapp.Jobs(lazyjobs.Config{...}) for static job configs, or return a config from a function when a durable backend needs context values such as a PostgreSQL pool.
  • Separate control-plane listeners now serve a compact GET / index that lists the registered control-plane endpoints. Same-listener control planes keep application / routes untouched. Read Control Plane.
  • The development panel now visits one resource-backed page per top-level tab and keeps the bottom status bar mounted as a permanent Turbo frame while you move between tabs. Read Development Panel and Lazydev Mode.
  • Development panel tabs now hydrate list content through their turbo-stream-source connection and then send targeted row or count updates only when a relevant backend event exists, avoiding whole-tab refreshes from unrelated build events.
  • The Routes tab now reads the app lazydev control plane and renders a filterable route table with method, path, route name, controller target, route params, and namespace metadata. Route searches use debounced backend Turbo Frame requests that cancel older in-flight searches.
  • Lazydev now exposes the running app's Go module build information at GET /buildinfo, and the development panel's BuildInfo tab shows the app Go version, command path, main module, dependencies, replacements, and recorded build settings. lazy also captures the Go command's build trace for each lazydev build and summarizes fetch, load, cache, build, and link timing plus the top five slowest packages in a two-sided BuildInfo view with runtime details, settings, and dependencies behind right-side tabs.
  • Lazydev now exposes the running app's lazydeps graph at GET /dependencies, and the development panel's Dependencies tab shows service rows plus directed dependency edges, progressively enhanced into an SVG graph by Stimulus. The tab can also simulate shutdown by sending 10 requests per second to the app root for a configured delay, then marking /readyz not ready, showing active requests and connections, waiting for active requests to drain, and coloring services as each dependency is canceled.
  • The lazy development proxy now serves Chromium Automatic Workspace Folders metadata at /.well-known/appspecific/com.chrome.devtools.json, pointing Chrome DevTools at the app's app/js source folder.
  • The injected development-panel host script now exposes window.disableDevPanel() so the Chrome DevTools extension can hide the in-page panel and launcher after the inspected page has loaded.
  • The development proxy now injects hidden panel host markup into proxied app HTML, while devpanel_controller.js owns the in-page panel, spacer, launcher, resize, and extension state.
  • The in-page development panel launcher now uses the padded, yellow-backed GoLazy square logo in a rounded-square button, opens the panel on click, and stays hidden while the Chrome extension is active or the in-page panel is visible.
  • The Requests tab now reads captured .spans and .log.json request sidecars, lists captured request paths, filters by request path and request category on the app control plane, and opens lazy-loaded Headers, Tracing, and Logs detail tabs. The Tracing detail shows controller and view regions by default, can include framework regions, displays correlated logs, and renders a chronological flamegraph for the selected region.
  • The Requests Tracing detail now has a request status strip, an Include golazy toggle, a backend-sorted region metrics table, and a flamegraph scaled by the selected time, allocation, or memory metric. Flamegraph bars now use square classical flamegraph colors, keep span names inside the bars, and expose full timing and allocation details in tooltips. The flamegraph pane grows to the graph's full height after the region table reaches its compact minimum. Allocation and memory flamegraphs fall back to the request timeline when a trace has regions but no positive sampled metric values.
  • Lazydev request sidecars and the Requests tab now show per-region total and self duration plus sampled allocation bytes, malloc counts, and free counts.
  • Request trace rendering now stops parent-depth walks when captured span data contains cyclic parent links, so a damaged .spans sidecar cannot freeze the browser.
  • The development panel now uses one top tab bar, places the close button on the right, shows the app and services as status chips, opens the App tab from the app status chip, and moves app lifecycle state, changed-file groups, rebuild, restart, and open-app controls into that App tab.
  • The Services tab now renders a service tree with a synthetic App service, managed services, lifecycle scripts, and all discovered mise tasks. Service logs are capped at 100 rows, batched while streaming, parse JSON log lines into message and attributes columns, and show run numbers so repeated check attempts and restarted service runs are visible.
  • Managed service rows can now restart, stop, or start a service from the Services tree.
  • The Assets tab now lists lazy asset manifest entries and public paths, and filters them with debounced backend Turbo Frame requests that cancel older in-flight searches. Route searches use the same request pattern. The Requests filter keeps its tab stream and debounces updates to that turbo-stream-source URL instead. The Cache tab hydrates from its tab stream, observes lazydev cache hit/miss/set events, updates summary counters individually, appends newly observed keys, and shows per-key hit/set metadata when the backend exposes it.
  • The Console and App Logs tabs were removed; app logs are merged into the Services tab.
  • The development panel status bar now keeps its live status stream inside the permanent Turbo frame, so tab switches keep one long-lived status connection.
  • The development panel layout now uses Turbo morph refreshes with scroll preservation, so refreshes can patch the panel document without resetting the user's scroll position.
  • The development panel now remembers the last top-level tab in session storage and restores it when the embedded panel loads at the default App tab. Static GET route clicks from the Routes tab ask the injected host client to visit the app path with Turbo when available.
  • Embedded development panels can now be resized from their top edge, and the proxied page's bottom padding follows the selected panel height.
  • Development panel data tables now remember resized column widths, and rightward header drags continue compressing later columns after the immediate right column reaches its minimum width. Tables also scale columns proportionally when panes resize, grouped or multi-row headers resize their covered leaf columns proportionally, and frame-targeted row clicks update selected-row styling immediately.
  • The Requests toolbar now combines a DevTools-style path filter with request handler chips, includes All as the default handler filter, and removes the previous All, Framework, Assets, Other category filter row.
  • Closed in-page development panels now show a small yellow GoLazy launcher when the Chrome extension is not installed. The extension action toggles the inspected page's in-page panel, and the in-page panel hides while the GoLazy DevTools panel is open.
  • The status bar app chip now opens App, and selected service chips keep the same background as the rest of the status bar.
  • golazy.dev/lazymigrate provides backend-agnostic migration loading, source/backend diffing, up/down/redo planning, schema dump/load hooks, and a fake backend for tests. Real database backends and CLI wiring are deferred.

CLI and generated apps

  • lazy new now renames the generated command directory from cmd/app to cmd/<app-name> and rewrites template docs and build commands to match.
  • lazy new now trusts the generated app's mise.toml, runs mise install, validates with the current go on PATH, then initializes a fresh Git repository and commits the generated checkout with a command-local GoLazy identity.
  • lazy new checks https://golazy.dev/lazy.version before remote template generation, supports --skip-update-check, and accepts --version <version> for a specific sample app tag.
  • Generated apps pin their mise-managed age, sops, and usage helper versions instead of using latest, so fresh mise install runs do not need a release-list lookup to decide the version.
  • The sample app template now includes .skills/golazy-framework, a reusable agent-facing skill that explains GoLazy application anatomy, framework package responsibilities, routes, controllers, views, services, assets, development commands, and testing boundaries.
  • LAZY_MULTIVERSION=off disables app-version CLI handoff for local testing, replacing the previous global --skip-version-check flag.
  • Go subprocesses in lazy new, lazy, lazy routes, lazy upgrade, and the app build step of lazy native build use the current go on PATH. lazy js and lazy tailwind choose app package managers from active installed mise tools in pnpm, yarn, bun, node order. Mise-selected managers run through mise exec; apps without a usable mise package-manager tool fall back to direct npm / npx.
  • lazy js keeps app-owned app/js files readable and unbundled while still writing content-hashed lazyshaft assets and importmap entries. Manifest library entrypoints remain bundled. Read lazy js And js.toml.
  • lazy js now names app-owned browser modules relative to the app/js root. Layouts import app.js, generated Stimulus wiring imports controllers such as controllers/hello_controller.js, and importmaps point those stable names at hashed lazyshaft assets.
  • The default lazy development command runs go mod tidy before building the app only when Go workspace mode is inactive. If GOWORK or go env GOWORK points at an active workspace, lazy skips the tidy step.
  • The default lazy development command now uses compact progress output for proxy startup, generated-asset work, Go builds, and application starts while leaving the running app's own output attached to the terminal.
  • The default lazy development command now serves a GoLazy development panel at /_golazy/, keeps it available across build and runtime failures, and starts the target app's development control plane on a separate internal address for route inspection, view-cache reloads, and cache inspection.
  • The development client now keeps one reload stream and one panel event stream alive across Turbo visits instead of opening duplicate EventSource connections. The panel event endpoint also uses the framework SSE stream helper so normal response wrappers do not turn the stream into a false 500.
  • The lazy development proxy now accepts plain HTTP and HTTPS on the same public port. HTTP serves a local HTTPS setup page with OS-specific instructions and a GoLazy certificate authority download; after the browser trusts that CA, the page redirects to HTTPS and the development panel can use HTTP/2 for app requests and panel streams.
  • The development panel now uses a DevTools-style tabbed shell, carries app lifecycle, services, requests, assets, jobs, routes, and cache controls into that shell, and embeds itself as a fixed bottom iframe on proxied app pages instead of only showing a floating activator button. The unpacked Chrome DevTools extension now probes /_golazy/extension on the inspected site and embeds that site's /_golazy/ panel when the lazy development proxy is present. It also retries during page reloads, keeps the embedded panel iframe mounted during same-origin app navigation, exposes Chrome's automatic workspace metadata for app/js, and lets the extension icon select the GoLazy DevTools panel when DevTools is already open.
  • The embedded development panel can now be closed from the panel toolbar. Panel split panes use Stimulus-owned resize handles with left, right, top, and bottom directions plus pixel or percentage size bounds.
  • The default lazy development command now assigns X-Request-ID and traceparent before proxying app requests and starts the child app with OTEL trace and log exporters enabled for lazydev request artifacts.
  • lazy now passes local view and public roots to lazydev builds with build-time variables. Development assets are served from disk by logical path without permanent hashes or cache headers.
  • lazy dump <dataset> and lazy load <dataset> now coordinate local service data snapshots under datasets/<dataset>/<service>.dump. Services are resolved from lazy.toml or discovered :start mise tasks, and dump/load behavior stays app-owned through service tasks. Read Services and Datasets.
  • When local services are configured or discovered, lazy starts them as managed subprocesses in parallel, records stdout and stderr, waits on available check tasks, runs create and migrate when present, and stops the app before stopping services on interrupt. Read Lazy.
  • The development panel now includes a Services tab with per-service stdout/stderr rows, lifecycle-script output, run numbers, and bottom status-bar indicators that open the selected service output. Each service row can restart, stop, or start that managed service.
  • View-only changes in lazy development now reload the running app's view cache through POST /views on the app's development control plane instead of rebuilding and restarting the app. Public-only changes reload the browser without rebuilding because development assets are read from disk.
  • lazy upgrade includes the older dependency initializer and SEO initializer migrations, the v0.1.17 controller/cache migration, and the v0.1.18 jobs module update path. It also uses compact progress output while still letting conflict diffs and prompts take over the terminal deliberately. Read the Upgrade Guide.
  • lazy upgrade applies go.mod dependency manifests with go get instead of rewriting module files directly, and it updates mise.toml tools through a tool manifest that comments obsolete entries rather than deleting them.
  • lazy upgrade file manifests now hash sample-app additions, replacements, and removals. Unchanged template-owned files are updated or removed directly, new files are created directly, and customized files ask for a dated backup, deletion, keep, or abort choice depending on the operation.
  • lazy --version now reports v0.1.18, so lazy new selects the matching sample application template for the latest released guide set.

Website and guides

  • Package documentation headings now link directly to the matching GitHub source line when source metadata is available, while the hover/focus ΒΆ link remains the in-page permalink.
  • Guide code blocks now load their Highlight.js language modules through the local lazyshaft importmap, covering Go, TOML, text, shell, SQL, and the other latest-guide fence languages without unresolved browser module specifiers.
  • The public installer installs golazy.dev/lazy, writes the binary to a predictable local bin directory when GOBIN is not set, tries the official shell-specific mise installer for bash, zsh, or fish, falls back to the plain bootstrap, and points new apps at lazy. Its same-shell recovery path now keeps lazy on the normal PATH so direct Go subprocesses still find go.
  • The homepage and package pages emit richer social-card metadata using the new SEO helpers.
  • The latest guides document the current v0.1.18 guide set while older versioned directories stay frozen as release snapshots.

Read the Upgrade Guide before moving an existing application forward.