---
area: "Learn"
parent: "Learn"
url: "https://unpoly.com/learn/network"
---
<nav aria-label="Unpoly docs">[All docs](https://unpoly.com/index.md) · [Learn](https://unpoly.com/learn.md)</nav>

# Network & caching

All of Unpoly's requests go through one HTTP client. It caches responses so revisited pages render instantly, revalidates cached content so stale data is quickly replaced, aborts requests that would race each other, and handles disconnects without the browser's error screen. This works without setup, and every part can be changed for a single link, a form or your whole app.

<nav aria-label="Contents">

#### Contents

- [How Unpoly makes requests](#how-unpoly-makes-requests)
- [Instant revisits from the cache](#instant-revisits-from-the-cache)
- [Aborting conflicting requests](#aborting-conflicting-requests)
- [Handling disconnects](#handling-disconnects)
- [Making requests from JavaScript](#making-requests-from-javascript)
- [See also](#see-also)

</nav>

## How Unpoly makes requests {#how-unpoly-makes-requests}

When the user follows a link or submits a form, Unpoly requests the URL without leaving the page:

```html
<a href="/preferences" up-target=".content">Preferences</a>
```

The request is a plain HTTP request. It carries [extra headers](https://unpoly.com/api/up.protocol.md) that tell the server what Unpoly intends to do with the response, like the targeted selector:

```http
GET /preferences HTTP/1.1
X-Up-Target: .content
```

The server renders a full HTML page, as it would for any browser request. Unpoly extracts the `.content` fragment from the response and swaps it into the page. A server may use the headers to [omit content that is not targeted](https://unpoly.com/learn/optimizing-responses.md), but it never has to.

Requests from links, forms, [polling](https://unpoly.com/learn/polling.md) and [preloading](https://unpoly.com/learn/preloading.md) all pass through the same client. They share one cache, one queue that limits concurrent requests, and one set of [events](https://unpoly.com/api/up.network.md).

## Instant revisits from the cache {#instant-revisits-from-the-cache}

When [navigating](https://unpoly.com/learn/navigation-defaults.md), responses to `GET` requests are cached. When the user returns to a page they already saw this session, the fragment renders from the cache, without waiting for the network:

```html
<a href="/stories/5" up-follow>Read story</a>
```

Following this link the first time fills the cache. Following it again renders instantly.

When the cached content may be outdated, Unpoly reloads the fragment from the server right after rendering it. The user sees the cached version immediately and the fresh version a moment later. This is called _revalidation_. Content counts as outdated after 15 seconds, or as soon as the user submits a form with a method like `POST`, since that has probably changed data on the server.

<nav aria-label="Read more">

- [More: Caching](https://unpoly.com/learn/caching.md)

</nav>

## Aborting conflicting requests {#aborting-conflicting-requests}

When a request is sent for a fragment that is still waiting for an earlier request, the earlier request is aborted:

```html
<a href="/pages/a" up-target="article">A</a>
<a href="/pages/b" up-target="article">B</a>
```

When the user clicks _A_ and then _B_ before _A_ has loaded, the request for _A_ is aborted. Only the response to _B_ is rendered, regardless of which response arrives first. Requests targeting other fragments are not affected.

Links and forms can change this rule with an `[up-abort]` attribute. For example, `[up-abort="layer"]` aborts every request on the current layer.

<nav aria-label="Read more">

- [More: Aborting requests](https://unpoly.com/learn/aborting-requests.md)

</nav>

## Handling disconnects {#handling-disconnects}

When the device is offline, clicking a regular link replaces your app with the browser's error page. Clicking an Unpoly link leaves the page as it is. Instead an [`up:fragment:offline`](https://unpoly.com/api/up:fragment:offline.md) event is emitted, which you can use to retry or to show a message:

```js
up.on('up:fragment:offline', function(event) {
  if (confirm('You are offline. Retry?')) event.retry()
})
```

Requests that time out are handled the same way. Pages already in the cache remain accessible while offline.

<nav aria-label="Read more">

- [More: Handling network issues](https://unpoly.com/learn/network-issues.md)

</nav>

## Making requests from JavaScript {#making-requests-from-javascript}

To use the HTTP client from your own code, call [`up.request()`](https://unpoly.com/api/up.request.md). It returns an [`up.Request`](https://unpoly.com/api/up.Request.md) object, which is also a promise for an [`up.Response`](https://unpoly.com/api/up.Response.md):

```js
let response = await up.request('/search', { params: { query: 'sunshine' } })
console.log(response.text)
```

These requests share the cache, the request queue and the events of requests made by links and forms. Pass `{ cache: true }` to read from and write to the cache. The promise rejects with the [`up.Response`](https://unpoly.com/api/up.Response.md) when the server responds with an error code, and with an [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) when the request is aborted, times out or the device is offline.

Every request emits events throughout its lifecycle. For example, listeners to [`up:request:load`](https://unpoly.com/api/up:request:load.md) can change a request before it is sent:

```js
up.on('up:request:load', function(event) {
  event.request.headers['X-Client-Time'] = Date.now().toString()
})
```

## See also {#see-also}

Requests the user is not waiting for, like preloading or polling, load in the background. See [Background requests](https://unpoly.com/learn/background-requests.md).

When the server responds with an error code, Unpoly renders the response with separate options. See [Handling error responses](https://unpoly.com/learn/error-responses.md).

<nav aria-label="In this chapter">

## In this chapter {#children-index-title}

- [Caching](https://unpoly.com/learn/caching.md)
- [Aborting requests](https://unpoly.com/learn/aborting-requests.md)
- [Background requests](https://unpoly.com/learn/background-requests.md)
- [Handling network issues](https://unpoly.com/learn/network-issues.md)

</nav>

<nav aria-label="Reading order">

- [Previous: Focus ring visibility](https://unpoly.com/learn/focus-visibility.md)
- [Next: Caching](https://unpoly.com/learn/caching.md)

</nav>

