---
title: server$ | Qwik Router
contributors:
  - mhevery
  - manucorporat
  - AnthonyPAlicea
  - saisrikardumpeti
  - igorbabko
  - RaeesBhatti
  - mrhoodz
  - DanielAdolfsson
  - mjschwanitz
  - wtlin1228
  - adamdbradley
  - jemsco
  - patrickjs
updated_at: '2024-05-11T17:00:00Z'
created_at: '2023-03-29T02:35:29Z'
---

import { Note, LongNote } from '~/components/note/note';

# `server$()`

`server$()` allows you to define functions that execute exclusively on the server, making it ideal for server-only operations and database access. It functions as an RPC (Remote Procedure Call) mechanism between the client and server. This is similar to a traditional HTTP endpoint, but strongly typed with TypeScript and easier to maintain.

<Note>`server$` can accept any number of arguments and return any value that can be serialized by Qwik. This includes primitives, objects, arrays, bigint, JSX nodes, and even Promises, just to name a few.</Note>

## Server-only modules

Qwik treats files named `.server.*`, such as `db.server.ts`, and files inside
`src/**/server/**` folders as server-only modules. These modules can be imported by SSR code,
route loaders, route actions, endpoint handlers, and `server$` implementations, but the client
build will fail if client code imports them.

```ts title="src/db.server.ts"
export const loadSecret = async () => {
  return process.env.API_KEY;
};
```

```tsx title="src/routes/index.tsx"
import { routeLoader$ } from '@qwik.dev/router';
import { loadSecret } from '../db.server';

export const useSecret = routeLoader$(async () => {
  return loadSecret();
});
```

Do not import server-only modules from browser code such as components, event handlers, or visible
tasks. If client code needs to trigger server work, expose that work through `server$`, a route
action, or an endpoint.

`AbortSignal` is optional, and allows you to cancel a long running request by terminating the connection.  
Your new function will have the following signature:  
`([AbortSignal, ...yourOtherArgs]): Promise<T>`  
<Note>Depending on your server runtime, the function on the server may not terminate immediately. It depends on how client disconnections are handled by the runtime.</Note>

```tsx
import { component$, useSignal, $  } from '@qwik.dev/core';
import { server$ } from '@qwik.dev/router';

// By wrapping a function with `server$()` we mark it to always
// execute on the server. This is a form of RPC mechanism.
export const serverGreeter = server$(
  function (firstName: string, lastName: string) {
    const greeting = `Hello ${firstName} ${lastName}`;
    console.log('Prints in the server', greeting);
    return greeting;
  }
);

export default component$(() => {
  const firstName = useSignal('');
  const lastName = useSignal('');

  return (
    <section>
      <label>First name: <input bind:value={firstName} /></label>
      <label>Last name: <input bind:value={lastName} /></label>

      <button
        onClick$={
          $(async () => {
            const greeting = await serverGreeter(firstName.value, lastName.value);
            alert(greeting);
          })
        }
      >
        greet
      </button>
    </section>
  );
});
```

## Accessing Request Information with `RequestEvent`

When using `server$`, you have access to the `RequestEvent` object through `this`. This object provides useful information about the HTTP request, including environment variables, cookies, URL, and headers. Here's how you can use it:

### Environment Variables

You can access environment variables using `this.env.get()`.

```tsx
export const getEnvVariable = server$(
  function () {
    const dbKey = this.env.get('DB_KEY');
    console.log('Database Key:', dbKey);
    return dbKey;
  }
);
```

### Cookies

You can read cookies using `this.cookie.get()` and `this.cookie.set()`.

<Note>When using `handleCookies` (in our example below) if it’s used within a `useTask$` function that runs during the initial request, setting cookies won’t work as expected. This is because, during server-side rendering (SSR), the response is streamed, and HTTP requires all headers to be set before sending the first response. However, if handleCookies is used in useVisibleTask$, this issue doesn’t occur. If you need to set cookies for the initial document request you can use `plugin@<name>.ts` or Middleware.</Note>

```tsx
export const handleCookies = server$(
  function () {
    const userSession = this.cookie.get('user-session')?.value;
    if (!userSession) {
      this.cookie.set('user-session', 'new-session-id', { path: '/', httpOnly: true });
    }
    return userSession;
  }
);
```

### URL

You can access the request URL and its components using `this.url`.

```tsx
export const getRequestUrl = server$(
  function () {
    const requestUrl = this.url;
    console.log('Request URL:', requestUrl);
    return requestUrl;
  }
);
```

### Headers

You can read headers using `this.headers.get()`.

```tsx
export const getHeaders = server$(
  function () {
    const userAgent = this.headers.get('User-Agent');
    console.log('User-Agent:', userAgent);
    return userAgent;
  }
);
```

### Using Multiple RequestEvent Information

Here's an example that combines environment variables, cookies, URL, and headers in a single function.

```tsx
export const handleRequest = server$(
  function () {
    // Access environment variable
    const dbKey = this.env.get('DB_KEY');

    // Access cookies
    const userSession = this.cookie.get('user-session')?.value;
    if (!userSession) {
      this.cookie.set('user-session', 'new-session-id', { path: '/', httpOnly: true });
    }

    // Access request URL
    const requestUrl = this.url;

    // Access headers
    const userAgent = this.headers.get('User-Agent');

    console.log('Environment Variable:', dbKey);
    console.log('User Session:', userSession);
    console.log('Request URL:', requestUrl);
    console.log('User-Agent:', userAgent);

    return {
      dbKey,
      userSession,
      requestUrl,
      userAgent
    };
  }
);
```

## Streaming Responses

`server$` can return a stream of data by using an async generator function, which is useful for streaming data from the server to the client.

Terminating the generator on the client side (e.g., by calling `.return()` on the generator or by breaking out from your async for-of loop) will terminate the connection. Similar to `AbortSignal`, how the generator terminates on the server side depends on the server runtime and how client disconnects are handled.

```tsx
import { component$, useSignal, $ } from '@qwik.dev/core';
import { server$ } from '@qwik.dev/router';

export const streamFromServer = server$(
  // Async Generator Function
  async function* () {
    // Creation of an array with 10 undefined values
    const iterationRange = Array(10).fill().entries(); 
  
    for (const [value] of iterationRange) {
      // Yield returns the array value during each iteration
      yield value;
  
      // Waiting for 1 second before the next iteration
      // This simulates a delay in the execution
      await new Promise((resolve) => setTimeout(resolve, 1000));
    }
  }
);


export default component$(() => {
  const message = useSignal('');
  return (
    <div>
      <button
        onClick$={
          $(async () => {
            // call the async stream function and wait for the response
            const response = await streamFromServer(); 
            // use a for-await-of loop to asynchronously iterate over the response
            for await (const value of response) {
              // add each value from the response to the message value
              message.value += ` ${value}`;
            }
            // do anything else
          })
        }
      >
        start
      </button>
      <div>{message.value}</div>
    </div>
  );
});
```

This API is actually used to implement QwikGPT streaming responses in our docs site.


## How does `server$()` work?

`server$()` wraps a function and returns an async proxy to the function. On the server, the proxy function directly calls the wrapped function, and a HTTP endpoint is automatically created by the `server$()` function.

On the client, the proxy function invokes the wrapped function via an HTTP request, using `fetch()`.

<Note>The `server$()` function must ensure that the server and client have the same version of the code executing. If there is a version skew the behavior is undefined and may result in an error. If version skew is a common problem then a more formal RPC mechanism should be used such as a tRPC or other library.</Note>

<LongNote title="Important Gotcha">
When defining and calling `server$()` inside an `onClick$`, be aware that this can lead to potential errors. To avoid them, make sure the handlers have `$` wrapped around them.

Don't do this: `onClick$={() => server$(() => // some server code!)}`

Do this: `onClick$={$(() => server$(() => // some server code!))}`
</LongNote>

## Middleware and `server$`

When using `server$`, it's important to understand how [middleware functions](/docs/middleware/#middleware-function) are executed. Middleware functions defined in `layout` files do not run for `server$` requests. This can lead to confusion, especially when developers expect certain middleware to be executed for both page requests and `server$` requests.

To ensure that a middleware function runs for both types of requests, it should be defined in the `plugin.ts` file. This ensures that the middleware is executed consistently for all incoming requests, regardless of whether they are normal page requests or `server$` requests.

By [defining middleware in the `plugin.ts`](/docs/advanced/plugins) file, developers can maintain a centralized location for shared middleware logic, ensuring consistency and reducing potential errors or oversights.
