---
title: "Server & SSR"
description: "Access Convex from Nitro handlers, run authenticated server calls, and preload data for hydration-safe SSR."
canonical_url: "https://nuxt-backend.dev/docs/data/server-rendering"
---
# Server & SSR

> Access Convex from Nitro handlers, run authenticated server calls, and preload data for hydration-safe SSR.

The module auto-imports a set of server utilities in the `server/` directory and Nitro handlers. They mirror the official `convex/nextjs` API surface. There is no server-side injected Convex client — all server access goes through these helpers. `api` itself is not auto-imported on either side: import it from [`#backend/api`](https://nuxt-backend.dev/docs/reference/nuxt/import-aliases).

## Fetching data on the server

```ts [server/api/example.ts]
import { api } from '#backend/api'

export default defineEventHandler(async () => {
  const messages = await fetchQuery(api.messages.list, {})
  await fetchMutation(api.messages.send, { body: 'From server' })
  const result = await fetchAction(api.images.generate, { prompt: 'cat' })
  return messages
})
```

<table>
<thead>
  <tr>
    <th>
      Function
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        fetchQuery
      </code>
    </td>
    
    <td>
      Run a query (optionally pass <code>
        { token }
      </code>
      
       for auth)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        fetchMutation
      </code>
    </td>
    
    <td>
      Run a mutation (optionally pass <code>
        { token }
      </code>
      
       for auth)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        fetchAction
      </code>
    </td>
    
    <td>
      Run an action (optionally pass <code>
        { token }
      </code>
      
       for auth)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        preloadQuery
      </code>
    </td>
    
    <td>
      Preload query data for SSR
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        preloadedQueryResult
      </code>
    </td>
    
    <td>
      Extract the result from a preloaded payload
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        backendAuth
      </code>
    </td>
    
    <td>
      Authenticated server helpers for the current H3 event
    </td>
  </tr>
</tbody>
</table>

## Authenticated calls — `backendAuth(event)`

`backendAuth(event)` is the Nuxt/Nitro equivalent of the official Next helper. It can fetch the Convex auth token, check authentication, run authenticated queries/mutations/actions, and preload authenticated data.

```ts [server/api/profile.ts]
import { api } from '#backend/api'

export default defineEventHandler(async (event) => {
  const auth = backendAuth(event)

  if (!await auth.isAuthenticated()) {
    throw createError({ statusCode: 401, statusMessage: 'Unauthorized' })
  }

  return auth.fetchAuthQuery(api.users.me, {})
})
```

`backendAuth(event)` returns these helpers:

<table>
<thead>
  <tr>
    <th>
      Helper
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        handler
      </code>
    </td>
    
    <td>
      Proxy Better Auth requests from Nuxt to the Convex site URL
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        getToken
      </code>
    </td>
    
    <td>
      Fetch a Convex auth token from the Better Auth session
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        isAuthenticated
      </code>
    </td>
    
    <td>
      Whether the current request has an authenticated Convex token
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        fetchAuthQuery
      </code>
    </td>
    
    <td>
      Run an authenticated Convex query
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        fetchAuthMutation
      </code>
    </td>
    
    <td>
      Run an authenticated Convex mutation
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        fetchAuthAction
      </code>
    </td>
    
    <td>
      Run an authenticated Convex action
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        preloadAuthQuery
      </code>
    </td>
    
    <td>
      Preload an authenticated query for <code>
        usePreloadedAuthQuery
      </code>
    </td>
  </tr>
</tbody>
</table>

<tip>

Use `auth.getToken()` if you need to pass the token to a lower-level `fetchQuery`/`fetchMutation`/`fetchAction` call yourself.

</tip>

## Preloading for SSR

`preloadQuery` returns a `Preloaded<Query>` payload designed to be passed back to app code and consumed with `usePreloadedQuery` — the server result is shown immediately, then the client goes live.

```ts [server/api/messages.preload.ts]
import { api } from '#backend/api'

export default defineEventHandler(async () => {
  return preloadQuery(api.messages.list, {})
})
```

```vue
<script setup lang="ts">
const { data: preloaded } = await useFetch('/api/messages.preload')
const messages = usePreloadedQuery(preloaded.value!)
</script>
```

### Authenticated preloading

For auth-protected data, preload through `backendAuth(event)` and hydrate with `usePreloadedAuthQuery`:

```ts [server/api/account.preload.ts]
import { api } from '#backend/api'

export default defineEventHandler((event) => {
  return backendAuth(event).preloadAuthQuery(api.auth.getAuthUser, {})
})
```

```vue
<script setup lang="ts">
const { data: preloaded } = await useFetch('/api/account.preload')
const currentUser = usePreloadedAuthQuery(preloaded.value!)
</script>
```

`usePreloadedAuthQuery` keeps the server result visible while Convex auth is loading in the browser, skips the live query if the user is unauthenticated, and switches to the live authenticated query once client auth is ready.


## Sitemap

See the full [sitemap](https://nuxt-backend.dev/sitemap.md) for all pages.
