---
url: >-
  https://lit-ui-router.dev/reference/ui-router-server/fetch/functions/createFetchHandler.md
---
[ui-router-server](../../index.md) / [fetch](../index.md) / createFetchHandler

# Function: createFetchHandler()

```ts
function createFetchHandler<R, Args>(router, options): FetchHandler<Args>;
```

Defined in: [fetch.ts:476](https://github.com/simshanith/lit-ui-router/blob/740888c2b2ba358c4dfa52a122e927df6a604b12/packages/ui-router-server/src/fetch.ts#L476)

Wraps a [ServerRouter](../../index/interfaces/ServerRouter.md) as a WinterCG fetch handler. `resolve()` is always
async (the simulate tier's lazy boundary), which fetch absorbs naturally —
with matcher-tier mounts nothing async ever actually runs.

* `redirect` -> `Response(null, { status, Location })`, the request's search
  MERGED into the location via [mergeSearch](../../index/functions/mergeSearch.md) (targets that declare their
  own query keep it — never `?a=1?b=2`).
* `shell` -> [serveShell](../interfaces/FetchAdapterOptions.md#serveshell) on a Request rewritten to [shellPath](../interfaces/FetchAdapterOptions.md#shellpath), the raw
  asset Response wrapped with a `Link: <mount>; rel="canonical"` header (the
  shell is the same representation at every route path).
* `shell` with status (the otherwise projection) -> validators stripped, the
  asset Response's status relabeled to the verdict's, no canonical Link (a
  404 is not an alternate representation of the mount root).
* `notFound` with a mount -> [serveNotFound](../interfaces/FetchAdapterOptions.md#servenotfound) (honest 404).
* `delegate`, for any request -> the handler [delegates](../interfaces/FetchAdapterOptions.md#delegates) maps its key to,
  called with the original request and the handler's own extra arguments
  (`handler(request, env, ctx)` reaches `delegate(request, env, ctx)`); its
  Response goes out untouched and its throw propagates to the host.
* `response`, for a GET or HEAD of any Accept -> [serveResponse](../interfaces/FetchAdapterOptions.md#serveresponse),
  its Response untouched; any other method -> 405.
* `notFound` without a mount, or a non-navigation request that matches no
  delegating or response state -> `null` (the host serves it however it
  would have). Non-navigations only match urls, never a transition, and
  skip matching when the router names no delegate keys or response states.

`R` is the router's type and `Args` the host's extra handler arguments;
write both (`createFetchHandler<typeof router, [Env]>`) or annotate the
result (`const handle: FetchHandler<[Env]> = …`), so the router's delegate
keys stay checked.

## Type Parameters

| Type Parameter | Default type |
| ------ | ------ |
|  `R` *extends* [`ServerRouter`](../../index/interfaces/ServerRouter.md)<[`RouteDeclaration`](../../redirects/interfaces/RouteDeclaration.md)> | - |
|  `Args` *extends* `unknown`\[] | \[] |

## Parameters

| Parameter | Type |
| ------ | ------ |
| `router` | `R` |
| `options` | [`FetchAdapterOptions`](../interfaces/FetchAdapterOptions.md)<`Args`, [`ServerRouterDeclarations`](../../index/type-aliases/ServerRouterDeclarations.md)<`R`>> & [`RequiredDelegates`](../type-aliases/RequiredDelegates.md)<`Args`, [`ServerRouterDeclarations`](../../index/type-aliases/ServerRouterDeclarations.md)<`R`>> & [`RequiredServeResponse`](../type-aliases/RequiredServeResponse.md)<`Args`, [`ServerRouterDeclarations`](../../index/type-aliases/ServerRouterDeclarations.md)<`R`>> |

## Returns

[`FetchHandler`](../type-aliases/FetchHandler.md)<`Args`>

## Throws

at construction when the router names a delegate key
[delegates](../interfaces/FetchAdapterOptions.md#delegates) lacks, or declares a
response state without [serveResponse](../interfaces/FetchAdapterOptions.md#serveresponse)
