Project Structure
A What project is a directory of HTML files and assets. Every folder has a purpose, and file paths map directly to routes.
Directory Layout
A typical project looks like this:
my-app/
what.toml # Project configuration
site/ # Pages — file paths become routes
index.html # /
about.html # /about
blog/
index.html # /blog
[id].html # /blog/:id (dynamic route)
application.what # Config for all pages in blog/
components/ # Reusable HTML components
card.html # becomes <what-card>
modal.html # becomes <what-modal>
partials/ # HTML fragments for w-get
static/ # Static assets (CSS, JS, images)
data/ # SQLite database, JSON collections
uploads/ # User-uploaded files
emails/ # Email templates
tests/ # Test files for run-what test
Every directory is optional. Start with just site/ and add others as you need them.
| Directory | Purpose |
|---|---|
site/ | Pages. Each .html file is a route. Subdirectories create nested paths. |
components/ | Reusable HTML components. card.html becomes the <what-card> tag. |
partials/ | HTML fragments loaded via w-get for dynamic content swaps. |
static/ | CSS, JavaScript, images, fonts. Served as-is at /static/*. |
data/ | Application data. SQLite database and JSON collections. |
uploads/ | Files uploaded through <form> with file inputs. Served at /uploads/*. |
emails/ | HTML templates for outgoing emails. |
tests/ | Test definitions for the run-what test command. |
what.toml
The project configuration file lives at the root. All fields are optional with sensible defaults.
[server]
port = 8085
[session]
enabled = true
cookie_name = "w_session"
max_age = 604800
database = "data/sessions.db"
[cache]
enabled = true
ttl = 300
what.toml entirely. The defaults work out of the box. You only need it when customizing ports, sessions, or deployment settings.
File-Based Routing
Every .html file in site/ becomes a route. The mapping is direct:
| File | Route |
|---|---|
site/index.html | / |
site/about.html | /about |
site/blog/index.html | /blog |
site/blog/[id].html | /blog/:id |
site/docs/[...slug].html | /docs/* (catch-all) |
Dynamic Routes
Square brackets create dynamic segments. The captured value is available as a template variable:
<what>
fetch.post = "local:posts?id=#params.id#"
</what>
<h1>#post.title#</h1>
<p>#post.body#</p>
Visiting /blog/42 sets #params.id# to 42, which is then used to fetch the matching post.
Index Files
A file named index.html in any directory serves as that directory's root. Both /blog and /blog/ resolve to site/blog/index.html.
application.what
An application.what file configures all pages within its directory (and subdirectories). It controls layout inheritance, authentication, and shared settings.
layout = "components/main-layout.html"
Every page in site/ now uses main-layout.html as its layout. You can override this per-directory or per-page.
Auth Directives
Restrict access to an entire directory:
layout = "components/admin-layout.html"
auth = "admin"
All pages under site/admin/ now require the admin role. Unauthenticated users get redirected to the login page.
Inheritance
Settings cascade from parent to child directories. A nested application.what can override or extend the parent:
site/
application.what # layout = "main-layout.html"
admin/
application.what # auth = "admin" (inherits main-layout)
settings/
application.what # layout = "settings-layout.html" (overrides layout)
Individual pages can also override with a <what> block:
<what>
auth: all
</what>
<h1>Public Report</h1>
<p>This page is accessible to everyone, even though it's in /admin.</p>
Static Files
Files in the static/ directory are served at /static/*:
static/
style.css # /static/style.css
app.js # /static/app.js
images/
logo.png # /static/images/logo.png
Reference them in your pages with absolute paths:
<link rel="stylesheet" href="/static/style.css">
<img src="/static/images/logo.png" alt="Logo">
<style> or <script> blocks in your page instead.