The schema is the app
In the first post I described the idea: Formless is a schema-as-data app runtime.
This post is the slower version. What does that actually mean? What goes in the schema? What does the runtime do with it? And which layers of normal app boilerplate disappear when the schema carries more intent?
1. Start with an entity
Most apps start with a model.
In a conventional stack, the same concept gets described several times:
database table
ORM model
validation schema
API request/response types
form fields
labels and help text
client-side state shape
display formatting
In Formless, the entity starts as runtime data:
{
"entities": {
"task": {
"label": "Task",
"fields": {
"title": {
"type": "text",
"label": "Title",
"required": true
},
"done": {
"type": "boolean",
"label": "Done",
"default": false
},
"dueDate": {
"type": "date",
"label": "Due date"
}
},
"mutations": {
"create": { "enabled": true },
"patch": { "enabled": true },
"delete": { "enabled": false }
}
}
}
}That is already more than a database shape. It describes storage-facing fields, validation, editor defaults, display labels, and mutation policy.
2. Add queries
A model is not enough. Apps need useful subsets of data.
{
"queries": {
"taskActive": {
"entity": "task",
"where": {
"field": "done",
"equals": false
}
},
"taskCompleted": {
"entity": "task",
"where": {
"field": "done",
"equals": true
}
}
}
}In a typical app, this logic might appear in an API route, a SQL query, a React selector, and a tab count calculation.
In Formless, it is named once. The runtime can use it for generated UI, local projections, and sync-safe display.
3. Add views
Queries say what records exist. Views say how people interact with them.
{
"views": {
"taskCreate": {
"type": "create",
"entity": "task",
"fields": {
"title": {},
"dueDate": {}
}
},
"taskHome": {
"type": "collection",
"entity": "task",
"groups": [
{
"label": "Active",
"query": "taskActive",
"createView": "taskCreate"
},
{
"label": "Completed",
"query": "taskCompleted"
}
]
}
}
}This is where the schema starts to feel like an app description rather than a data description.
The runtime now knows:
which records are visible
how they are grouped
which create form belongs to the collection
which fields should appear when creating records
which generic mutations are allowed
4. Add a screen
A screen turns views into routes and workspaces.
{
"screens": {
"taskHome": {
"type": "workspace",
"navigation": {
"primary": true,
"label": "Tasks"
},
"layout": {
"type": "stack",
"sections": [
{
"id": "tasks",
"type": "collection",
"view": "taskHome"
}
]
}
}
}
}At this point the schema can generate a usable app surface.
Not a mockup. A real route. Real records. Real create and patch flows. Local browser state. Authority-backed writes.
5. The runtime takes over the boring parts
The payoff is not that JSON is magically better than code. The payoff is that runtime code can become generic.
A normal stack often needs bespoke code for:
DB schema
ORM model
API create route
API patch route
API validation
request/response types
React query/cache wiring
form components
field labels
field validation messages
list filters
empty states
optimistic local updates
sync merge behavior
Formless tries to move the repeatable parts into the runtime.
The schema says:
what exists
what fields mean
what can be edited
what queries matter
what views should exist
what screens compose those views
what actions are valid
The runtime handles:
parsing the schema
validating writes
storing flat records
syncing browser replicas
generating editors
rendering collections
running generic create/patch mutations
dispatching named actions
6. Where this sits in the ecosystem
Formless overlaps with a few familiar layers, but it is not exactly any of them.
Compared to an ORM
An ORM maps code objects to storage.
Formless starts higher up. It describes the app model and interaction surface. Storage is one consumer of the schema, not the whole point.
Compared to validation libraries
Validation libraries answer: "is this input allowed?"
Formless wants the same field definition to also answer: "how should this be edited, displayed, labeled, defaulted, queried, and patched?"
Compared to generated admin tools
Admin generators usually introspect a database and give you CRUD.
Formless makes the authoring surface explicit in schema data: views, screens, relationships, read models, and actions are part of the app definition.
Compared to sync frameworks
Sync frameworks move data around.
Formless still needs sync, but the schema gives sync more context: records are keyed by schema app, mutations are generic, read models are display-only, and the authority owns invariants.
Compared to local state libraries
Local state libraries help the UI remember things.
Formless uses a browser replica as part of the runtime. The app state is not hand-modeled per screen; it is projected from schema, records, queries, and selected context.
7. Why this matters for agents
This is the agentic-world bit.
Agents work better when the app exposes a structured map of itself.
A schema can tell an agent:
these are the entities
these fields are editable
these fields are required
these relationships matter
these views are user-facing
these actions are valid commands
these values are computed, not stored
That is much better than asking an agent to infer product rules from scattered UI components, ORM models, route handlers, and validation helpers.
The schema becomes an interface. Not just for rendering UI, but for understanding and safely changing the app.
8. The honest boundary
Formless does not remove all code.
The current Site app still has a public renderer. The authority still owns invariants. Named actions still need runtime implementations. Complex product behavior still deserves real code.
The goal is narrower and more useful:
ordinary app structure should be data
specific domain behaviour should be code
the runtime should know the difference