Quick Start

Full App

Move from the one-file app into the conventional GoLazy application layout.

By Guillermo Alvarez - Published - Updated

Start from the generated layout

lazy new creates a conventional app:

app/
  controllers/
  public/
  views/
cmd/app/
init/
services/
test/

The split is intentionally small. cmd/app starts the process, init wires the app together, app holds the web presentation layer, and services holds core business behavior.

Keep main thin

The executable should only start the application:

func main() {
    if err := appinit.App().ListenAndServe(); err != nil {
        log.Fatal(err)
    }
}

That keeps tests able to construct the full handler without opening a network listener.

Wire the app once

init/app.go composes the app:

func App() *lazyapp.App {
    return lazyapp.New(lazyapp.Config{
        Name:    "sample_app",
        Drawer:  Draw,
        Public:  app.Public,
        Views:   app.Views,
        Context: Context,
    })
}

The app owns dependencies, routes, embedded views, and public files. The framework owns dispatch, rendering, asset registration, and route binding.

Put routes in one place

init/routes.go draws the route table:

func Draw(router *lazyroutes.Scope) {
    router.Get("/", home.New, (*home.HomeController).Index)
    router.Resources(postcontroller.New)
}

Controllers stay under app/controllers, views stay under app/views, and business services stay under top-level services.

Keep public outputs embeddable

Generated assets are committed under app/public:

app/public/styles.css
app/public/assets/importmap.json
app/public/assets/lazyshaft/

Run the asset commands before tests and builds when those inputs change:

lazy tailwind
lazy js
go test ./...

Continue with Application Structure for the full directory map.