Skip to content
Trilha
Chapters

Learn

Quick start

From zero to a page in the browser in five minutes, and what happened at each step.

In this trail you build an events agenda: a list, a detail page, a form to register events, a JSON API and a restricted area. Each chapter adds one piece and ends with a challenge. This first one only gets the project standing.

What you need#

  • Go 1.22 or newer (go version).
  • Go's binary directory on your PATH: ~/go/bin (Go installs programs there, not in /usr/local/go/bin, which is where go itself lives).
# if `trilha` is not found after go install, add this to your ~/.zshrc or ~/.bashrc:
export PATH="$HOME/go/bin:$PATH"

Install and create the project#

go install github.com/emersonjoe/trilha/cmd/trilha@latest
trilha new agenda
cd agenda
trilha dev

Open http://localhost:3000. The home page is already there. Leave trilha dev running: it recompiles and reloads the browser every time you save a file.

What was created#

agenda/
├── go.mod
├── trilha_gen.go          ← generated by the CLI; commit it, do not edit it
├── public/style.css       ← served at /style.css
└── app/
    ├── layout.go          ← the <html> of every page
    ├── page.go            ← GET /
    ├── not_found.go       ← 404 page
    └── api/hello/route.go ← GET /api/hello

The rule that holds everything together: a folder inside app/ is a path in the URL. The file inside it says what that path does.

Your first page#

Create app/events/page.go:

package events

import (
	"github.com/emersonjoe/trilha"
	"github.com/emersonjoe/trilha/h"
)

func Page(c *trilha.Ctx) (h.Node, error) {
	c.SetTitle("Events")
	return h.Fragment(
		h.H1(h.Text("Upcoming events")),
		h.P(h.Text("No events registered yet.")),
	), nil
}

Save and visit /events. Three things happened:

  1. The CLI saw the new folder, regenerated trilha_gen.go with the /events route and recompiled.
  2. Page ran and returned an HTML node, built with the h package.
  3. The node was handed to the Layout in app/layout.go, which wrapped it in <html>, and the result was sent with Content-Type: text/html.

Challenge#

Create app/about/page.go answering /about with a heading and a paragraph, and add a link to it in the navigation of app/layout.go. When you save, the page should appear without restarting anything.

Show solution
// app/about/page.go
package about

import (
	"github.com/emersonjoe/trilha"
	"github.com/emersonjoe/trilha/h"
)

func Page(c *trilha.Ctx) (h.Node, error) {
	c.SetTitle("About")
	return h.Fragment(
		h.H1(h.Text("About the agenda")),
		h.P(h.Text("An events agenda built with Trilha.")),
	), nil
}

In app/layout.go, inside h.Nav(...):

h.A(h.Href("/about"), h.Text("About")),