GizWeb
Full-stack apps from one typed model.
Declare a record type once. GizWeb derives the table, the form, the validation, the JSON API and the agent tool from it. Pages render on the server, a 1.2 KB kernel adds interaction, and open pages update when the data commits.
Coming In development. This is the design it ships to. Roadmap
One model, every layer
import {Table, Key, Label, Min, Max, Trim} from "gizdb:model";
@Table("todos")
export type Todo = {
@Key id: i64;
@Label("Title") @Min(1) @Max(200) @Trim title: string;
@Label("Done") done: bool;
};Model.shape<Note>() reads the Shape of a type from its declaration at run time: no generated file. From it you get:
| Layer | What GizWeb gives |
|---|---|
| Database | The table and its migrations. A field rename with @was keeps the data. |
| Forms | An HTML form with the labels, limits and errors of the fields. |
| Validation | The same checks on the server for browsers, the API and agents. |
| API | JSON input and output with typed rejections (401, 403, 404, 409, 422). |
| Agents | A tool schema for each Action. Agents call the same Action as people. |
Pages are typed markup
import {Html, each} from "gizlang:html";
type ListProps = { todos: Vec<Todo>; };
export function TodoList(p: ListProps): Html {
return <ul>{each(p.todos, (t: Todo) =>
<li data-k={string(t.id)}><input type="checkbox" checked={t.done}/> {t.title}</li>)}</ul>;
}Markup in .giz files has TSX syntax. It compiles to escaped HTML, so an injection needs an
explicit raw.
Why GizWeb
No hydration and no client framework. The comments app sends 26,157 B (9,448 B gzip) of JavaScript. The same app on Next.js 16 sends 592,598 B (196,717 B gzip).
A page subscribes to its data. When a row commits, the server sends a patch for the changed elements only. Typed text and focus stay.
Actions for people, APIs and agents
One typed function handles the form post, the JSON call and the agent tool call, with the same checks.
Pages, actions, static files, gzip and realtime in one native process, a worker for each CPU.
Declarative shadow DOM from the server, with no build step.
One call makes an app installable and usable offline. The same app compiles to WebAssembly for an edge fetch handler.
Markdown collections checked by a model, navigation, llms.txt, sitemaps, drafts and review. This site runs on it.
Site headers, docs layouts, tabs, callouts, data regions with loading, empty and failed states, time ranges and log views.
Measured against Next.js 16
| GizWeb | Next.js 16 | |
|---|---|---|
| Start-up to first page | 66 ms | 271 ms |
| Thread page, one CPU (Next.js: one process) | 1,739 req/s | 197 req/s |
| p99 latency, one CPU | 58.5 ms | 562 ms |
| JavaScript sent to the browser | 26,157 B (9,448 B gzip) | 592,598 B (196,717 B gzip) |
| Memory after load (PSS) | 68.3 MB | 378 MB |
The same threaded realtime comments app on GizWeb and on Next.js 16 (App Router, server actions, node:sqlite): the same pages, actions and session token, and 60 seeded comments. Each server is one process on 8 server CPUs; the load (bench/web/lib/load.c, 32 keep-alive connections) is on 8 other CPUs. GizWeb runs on one server CPU, then on a thread for each server CPU, with GizDB in the process. Throughput is the best of 3 runs.
GizDB in the process (`Data.database`).
These numbers come from our measurement notes of that date. The suite has not recorded them again yet.
This suite needs the GizStack sources, so the release does not carry it yet.
All the rows: benchmarks.
Next steps
Routes, layouts, forms, streaming, static files, sessions, tests and deployment.
One record type for the table, typed queries, forms and views.
Put the app at its own address, and change it live.