Unpoly lets your links and forms update fragments of the current page, instead of loading full new documents. Screens update without a full page load and keep their state. Your app stays on the server, rendering HTML with any language and any framework.
Here is a link enhanced with an Unpoly attribute:
<a href="/messages" up-target=".messages">Messages</a> <!-- mark: up-target=".messages" -->
When the user clicks, Unpoly fetches /messages without leaving the page.
Your server handles the request like any other, and responds with a full HTML page.
Unpoly extracts the .messages fragment from the response and swaps it into the current page.
The rest of the page is left untouched: scroll positions, focus, unsaved form fields and running scripts all survive the update.
Because the server renders full pages, each screen remains a page of its own. When the user opens the link in a new tab, or when JavaScript is unavailable, the browser makes a regular full page load.
To your backend, requests from Unpoly look like any browser request. There is no JSON API to build and no client-side templates to maintain. You keep rendering HTML on the server, with the routes and templates you already have.
You also don't need separate fragment endpoints: Unpoly takes the fragment it needs and discards the rest of the response. A server can choose to render only the requested fragment, but that is an optional optimization. Most screens never need it.
When a link or form updates the main fragment of the page, Unpoly treats the interaction as a navigation and mimics what a full page load would have done:
Each of these defaults can be changed, per element or globally.
The rest of this chapter is hands-on. After installing Unpoly, you will make one basic move in each area:
You will then learn the shape of the API: one pattern that all of Unpoly's features follow. Each step works on its own, so you can stop after any of them.
Tip Your coding agent can search these docs locally with the Unpoly agent skill