Getting Started

Set up a Vango app, understand the canonical project layout, and wire a basic server, layout, and page.

#setup#routing#project-structure

Getting Started

Vango is optimized for full-stack Go apps with server-owned UI state. The normal app flow is:

  1. create the app

  2. register routes and layouts

  3. keep page handlers thin

  4. push stateful logic into vango.Setup components

  5. let the browser connect to the runtime and apply patches

Canonical project structure

text
1myapp/
2|- cmd/
3|  `- server/
4|     `- main.go
5|- app/
6|  |- routes/
7|  |- components/
8|  |- stores/
9|  `- middleware/
10|- internal/
11|  |- services/
12|  |- db/
13|  `- config/
14|- public/
15|- vango.json
16|- vango_state_manifest.json
17|- vango_state_schema.json
18`- go.mod

Use this layout consistently:

  • app/routes owns route files

  • app/components owns shared UI

  • app/stores owns session keys and durable store-like surfaces

  • internal/services owns business logic and I/O

  • public owns static assets

Typical server entry point

go
1package main
2
3import (
4	"context"
5	"log"
6	"os"
7	"time"
8
9	"github.com/vango-go/vango"
10	"myapp/app/routes"
11)
12
13func main() {
14	app, err := vango.New(vango.Config{
15		Session: vango.SessionConfig{
16			ResumeWindow: vango.ResumeWindow(30 * time.Second),
17		},
18		Static: vango.StaticConfig{
19			Dir:    "public",
20			Prefix: "/",
21		},
22		DevMode: os.Getenv("VANGO_DEV") == "1",
23	})
24	if err != nil {
25		log.Fatal(err)
26	}
27
28	routes.Register(app)
29
30	if err := app.Run(context.Background(), ":3000"); err != nil {
31		log.Fatal(err)
32	}
33}

At startup, the usual sequence is:

  • load configuration

  • build dependencies

  • create the Vango app

  • wire auth or session hooks if needed

  • register routes

  • run the server

Basic layout

Layouts are pure wrappers. Keep them responsible for shell structure and bootstrap only.

go
1func Layout(ctx vango.Ctx, children vango.Slot) *vango.VNode {
2	return Html(
3		Head(
4			Meta(Charset("utf-8")),
5			Meta(Name("viewport"), Content("width=device-width, initial-scale=1")),
6			LinkEl(Rel("stylesheet"), Href(ctx.Asset("styles.css"))),
7		),
8		Body(
9			Main(children),
10			RuntimeScripts(ctx),
11		),
12	)
13}

Good layout responsibilities:

  • navigation

  • asset tags

  • shell structure

  • persistent banners

  • runtime scripts

If you need state in the layout, embed a Setup component inside it. Do not make the layout function itself imperative.

Basic page

Page handlers should stay thin.

go
1func IndexPage(ctx vango.Ctx) *vango.VNode {
2	return Div(Text("Hello from Vango"))
3}

That handler is a render-time function, not an imperative route-entry callback. Treat it like view selection.

File-based routing

Vango scans app/routes.

Common mappings:

  • app/routes/index.go -> /

  • app/routes/about.go -> /about

  • app/routes/projects/index.go -> /projects

  • app/routes/projects/id_/index.go -> /projects/:id

  • app/routes/docs/path___/index.go -> /docs/*path

  • app/routes/layout.go -> root layout

  • app/routes/api/*.go -> API endpoints

Prefer Go-friendly parameter directories like id_ and path___ instead of bracketed names.

  • route handlers choose the view

  • Setup components own state and lifecycle

  • Resources own reads

  • Actions own mutations

  • render computes UI from current state only

If you need the core contracts before you write more app code, read Mental Model next.