Skip to main content
Prefab apps can be backed by any HTTP server. Build your UI with components, serve it as HTML, and use Fetch to make HTTP requests back to your API routes. Client actions like SetState and ShowToast run instantly in the browser — Fetch handles the server round-trips. Prefab has no dependency on any web framework. This guide uses FastAPI, but the pattern works with anything that can serve HTML and JSON — Flask, Django, Starlette, or even a plain socket server.

Quick Start

A Prefab + FastAPI app has three kinds of routes:
  • Page routes return HTML — they build a component tree, wrap it in PrefabApp, and call .html()
  • Data routes return plain JSON (lists, dicts) — written into state via SetState in an on_success callback
  • Component routes return a component tree as JSON (via .to_json()) — rendered by a Slot
FastAPI is not bundled with Prefab. Install it separately: pip install fastapi uvicorn
Here’s a minimal app with a page route and a data route wired together with live search:
Run it with uvicorn app:app --reload and visit http://localhost:8000. Typing in the search box fires a GET /api/items?q=... request on every keystroke, and the results re-render automatically. PrefabApp.html() returns a self-contained HTML page with the renderer, component tree, and initial state baked in — no external assets or build step needed. The title parameter sets the browser tab title.
When an Input has on_change, you must include SetState to update the input’s value — the auto-sync is replaced by your custom handler. Use {{ $event }} to reference the current input value.

Patterns

Loading Data

Fetch.get makes a GET request. The parsed JSON response is available as $result (Python: RESULT) inside the on_success callback. Use SetState to write it into client-side state, and components that reference that key re-render automatically.
Pass query parameters with params — values support expression interpolation:

Submitting Data

Fetch.post sends a JSON body to your API. Wrap inputs in a Form so that pressing Enter triggers submission. Reference named inputs by assigning the component to a variable and using .rx, or create an Rx reference directly — make sure each key is initialized in your PrefabApp(state=...), otherwise unset values render as literal template strings.

Forms in Dialogs

For forms that shouldn’t clutter the main layout, put them inside a Dialog. Use CloseOverlay() in the success chain to dismiss the dialog after submission:
The first child of Dialog is the trigger element (the ”+ Add” button). Everything after it becomes the dialog’s body.

Deleting Data

Fetch.delete sends a DELETE request. Chain a Fetch.get in on_success to refresh the list after removal:

Dynamic Component Routes

Data routes return plain values that templates interpolate. But sometimes you want the server to return entire UI fragments — a detail panel, a chart, a custom card layout. That’s what component routes are for. A component route builds a component tree in Python and returns its JSON representation. On the client, a Slot renders whatever component tree lands in its state key:
The Slot shows its fallback children until a Fetch writes a component tree into the detail state key. This is the same pattern that CallTool uses in FastMCP — the server decides what to render, not just what data to return.

Error Handling

Non-2xx responses trigger on_error. The $error variable contains the status line (e.g., “400 Bad Request”), which you can surface with a toast or write to state for inline display:
On the server side, raise an HTTPException to return error status codes:

Loading States

Action chains execute sequentially and short-circuit on failure. Wrap a Fetch with SetState calls to show and hide a loading indicator:
If the request fails, the chain stops — SetState("saving", False) never runs. Handle cleanup in on_error if needed.

Refreshing After Mutations

After a successful POST or DELETE, you often want to reload the data list. Chain a Fetch.get inside on_success:

FastMCP vs API Server

Both use the same components and state model. The difference is how the UI talks to your server: If you’re building an MCP server, use CallTool. If you’re building a web app, use Fetch. The component tree and client-side actions are identical either way.

Example App

The examples/hitchhikers-guide directory contains a complete working app — a Hitchhiker’s Guide catalog with live search, dialog-based entry creation, inline deletion, and error handling. The same directory also contains a FastMCP version of the same app for comparison.