Skip to content

Quickstart: YAML only

A Mateu app whose UI is data: a few YAML files under src/main/resources/specs/ui/. You write no code — the only Java is the Spring Boot main class the generator gives you, and the static flavour has none at all.

You need Java 21 and Maven 3.9+.

Pick one front door (all of them generate the same project):

  • IntelliJ IDEA: File › New › Project… › Mateu, authoring YAML only, served by a backend.

  • VS Code: command palette › Mateu: New Project… › YAML only, served by a backend.

  • Maven:

    Terminal window
    mvn archetype:generate -DarchetypeGroupId=io.mateu -DarchetypeArtifactId=mateu-archetype \
    -DarchetypeVersion=<release> -DgroupId=com.acme -DartifactId=my-app -Dauthoring=yaml

It is the starters/yaml project of the repository, which CI builds and boots on every change.

Terminal window
cd my-app
mvn spring-boot:run

Open http://localhost:8080: an app shell with a menu (Home, Products) opening on a home page, whose Browse products button leads to a listing — search, a status filter, sorting and paging — over sample data.

my-app/
├── pom.xml Spring Boot + mateu-mvc + the renderer
├── AGENTS.md, CLAUDE.md guidance for AI assistants
└── src/main/
├── java/…/Application.java boots the server — nothing else
└── resources/specs/ui/
├── app.ui.yaml the mount: this app at "/", its routes, its home (`home: home`)
├── routes.yaml each route bound to a definition
├── app.yaml the app shell: title and menu
├── home.yaml a page: the home, with a call to action to the products
├── products.yaml a page: the listing
├── sources.yaml the REST endpoints, named once, with sample data
└── project.yaml project settings (the renderer)

The home page is a hero whose button navigates — its actionable is a RouteLink, so there is nothing behind it to run:

home.yaml
type: VerticalLayout
fullWidth: true
horizontalAlignment: STRETCH
content:
- type: HeroSection
title: My app
subtitle: Every screen here is declared as data, in src/main/resources/specs/ui.
centered: true
content:
- type: Button
label: Browse products
buttonStyle: primary
actionable:
type: RouteLink
route: products

The listing reads its rows from a named source:

products.yaml
type: Listing
title: Products
searchable: true
rowsSource:
ref: products
columns:
- {type: GridColumn, id: id, label: Id, identifier: true}
- {type: GridColumn, id: name, label: Name}
- {type: GridColumn, id: status, label: Status, dataType: status}
sources.yaml
sources:
- name: products
source:
url: /api/products
sample:
- {id: P-001, name: Espresso machine, price: 249.0, status: AVAILABLE}

Until your API exists the source answers with its sample: — the generated main class turns sample mode on. Point url at your API and run with -Dmateu.sources.mock=false to go live.

A screen is a definition file plus a route and, if it belongs in the menu, a menu entry:

  1. Create specs/ui/orders.yaml — in IntelliJ New › Mateu › Page… or in VS Code Mateu: New File… start it from a page template, then edit it in the visual editor.

  2. Add the route in routes.yaml (Add Route… in both IDEs):

    - route: orders
    layout: orders.yaml
  3. Add it to the menu in app.yaml:

    - type: RouteLink
    label: Orders
    route: orders

Every file carries a $schema line, so both IDEs validate and complete it.

Choose YAML only, static (no backend) instead (-Dauthoring=static) and the same specs/ui is bundled at build time into plain files:

Terminal window
mvn package # → target/mateu-bundle/: index.html, manifest.json, assets/
npx serve -s target/mateu-bundle # preview it at http://localhost:3000

Deploy target/mateu-bundle/ to any static host with an SPA fallback. The browser calls the APIs named in sources.yaml itself, so they must allow your site’s origin (CORS); .mvn/maven.config ships the sample data (-Dmateu.bundle.mock=true) until they exist. The build fails if a screen still needs a server. See A 100 % static UI.

  • Route registry — routes, parameters, nested routes.
  • REST source catalogue — endpoints, field mapping, writes, sample data.
  • The YAML app shell — menus, home route, header actions.
  • Need behaviour on the server for a screen? Bind a Java view model to its route (viewModel: in routes.yaml) — the Code + YAML flavour starts that way.