Iwf Guide
Your First Project
This guide creates the smallest useful Iwf app. You will generate a project, change the first page, add a route, add a table, and learn where generated code goes.
1. Generate The App
From the Iwf repository root:
iwf new my-app
cd my-app
iwf build
./build/exec/my-app
Open:
http://127.0.0.1:8080
The generated project contains:
| Path | Purpose |
|---|---|
src/Main.idrx |
The first page, route list, and server entry point. |
my-app.ipkg |
The Idris package file for the app. |
Application/Schema.sql |
PostgreSQL schema source of truth. |
Application/Fixtures.sql |
Development and test seed data. |
Application/Migrations/ |
Ordered SQL migrations. |
build/generated/ |
Generated Idris source. Do not edit this by hand. |
2. Change The First Page
Open src/Main.idrx.
Look for the page view and change the heading:
homeView : Html
homeView =
fragment
[ <title>My App</title>
, <main id="main-content" class="mx-auto flex max-w-3xl flex-col gap-6 p-6">
<section class="card">
<h1>Hello from Iwf</h1>
<p>Direct .idrx HTML is compiled into checked Idris.</p>
</section>
</main>
]
Rebuild and restart the executable:
iwf build
./build/exec/my-app
The build script preprocesses:
src/Main.idrx -> build/generated/Main.idr
Edit .idrx files. Do not edit generated .idr files under build/generated/.
3. Add A Route
Add another view and handler in src/Main.idrx:
aboutView : Html
aboutView =
fragment
[ <title>About</title>
, <main id="main-content" class="mx-auto max-w-3xl p-6">
<h1>About</h1>
<p>This page is rendered by Idris on the server.</p>
</main>
]
about : ControllerContext -> Response
about context =
render context aboutView
Add it to the route list:
export
htmlHomeRoute : RouteSpec NoInput NoInput Response
htmlHomeRoute =
get "/"
export
htmlHomeBinding : BoundRoute
htmlHomeBinding =
handledBy htmlHomeRoute home
export
htmlAboutRoute : RouteSpec NoInput NoInput Response
htmlAboutRoute =
get "/about"
export
htmlAboutBinding : BoundRoute
htmlAboutBinding =
handledBy htmlAboutRoute about
export
htmlRoutes : Routes
htmlRoutes =
[ htmlHomeBinding
, htmlAboutBinding
]
appRoutes : Routes
appRoutes =
htmlRoutes
Now visit:
http://127.0.0.1:8080/about
Internal links and forms are boosted by default. A direct browser request gets the framework shell plus this page content. An htmx request gets only the #main-content fragment.
4. Link To The New Route
Use the route value instead of spelling the URL again:
<a class="btn-primary" href={pathTo htmlAboutRoute}>About</a>
In a larger app, keep handlerless route specs in Web/Routes.idr, keep executable handledBy bindings in Web/RouteBindings.idr, and use pathTo from views. That way route changes update links at compile time instead of becoming broken URLs.
The canonical app shows this style:
homePath = pathTo htmlHomeRoute
articlePath = pathTo htmlArticleRoute (MkArticleSlugInput article.slug)
5. Add A Table
Open Application/Schema.sql and add:
CREATE TABLE articles (
id BIGSERIAL PRIMARY KEY,
slug TEXT NOT NULL UNIQUE,
title TEXT NOT NULL,
body TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT now()
);
Rebuild:
iwf build
The starter keeps the schema files in place even before the app uses the database. The canonical app shows the full schema/typegen flow where Application/Schema.sql generates Generated.Schema before compilation.
6. What To Study Next
After this starter works, build one full slice with First CRUD Feature. It keeps the code in the app-facing interface while adding a path route, form, table, TypedSQL query, validation, auth, and live fragment.
Then study examples/canonical. It shows the normal larger app shape:
Application/for schema, queries, mail, jobs, fixtures, and domain code.Web/Routes.idrfor route declarations.Web/Controller/*for request handlers.Web/View/*.idrxfor HTML.build/generated/for generated Idris modules.
Next
Read First CRUD Feature.