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/
  services/
  views/
cmd/app/
init/
test/

The split is intentionally small. cmd/app starts the process, init wires the app together, and app holds the behavior that serves requests.

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 services stay under app/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.