Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/purple-games-sleep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@vue3-apollo/docs": patch
---

docs: add guide for advanced Nuxt Apollo integration
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"dev:docs": "pnpm --filter @vue3-apollo/docs run dev",
"dev:nuxt": "pnpm --filter @vue3-apollo/nuxt run dev",
"dev:web": "pnpm --filter @vue3-apollo/web run dev",
"lint": "eslint .",
"lint": "eslint .",
Copy link

Copilot AI Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra whitespace added between 'eslint' and '.'. This appears to be an unintentional change and should be reverted to maintain consistency.

Suggested change
"lint": "eslint .",
"lint": "eslint .",

Copilot uses AI. Check for mistakes.
"lint:fix": "eslint . --fix",
"release": "pnpm build && changeset publish",
"typecheck": "pnpm run typecheck:core && pnpm run typecheck:nuxt && pnpm run typecheck:web",
Expand Down
4 changes: 4 additions & 0 deletions packages/docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ export default defineConfig({
},
{
items: [
{
link: '/advance/nuxt-custom-integration',
text: 'Nuxt Integration'
},
{
link: '/advance/tracking',
text: 'Tracking'
Expand Down
91 changes: 91 additions & 0 deletions packages/docs/advance/nuxt-custom-integration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Custom Apollo Integration for Nuxt


A compact guide for setting up and extending Apollo Client in Nuxt, focusing on module limitations, plugin customization, and best practices.

## Overview

Nuxt modules simplify setup but run only at **build time**, meaning they can’t access runtime APIs like `useRuntimeConfig` or `useApolloClient`.
For dynamic logic (auth, caching, token refresh), use **plugins**, which run after app startup with full Nuxt context.

## Why Use Plugins

### 1. Serialization
During build, Nuxt serializes module options into JSON.
Complex objects like `ApolloClient` or custom `Link`s **lose references** and can’t be reused at runtime.

### 2. Context Isolation
Modules execute in a **separate build context**, isolated from Nuxt’s runtime environment.
Plugins, on the other hand, run inside the live app, where you can modify the Apollo client safely.

**Modules:** define static config & generate runtime code
**Plugins:** handle runtime logic & modify live instances

## Basic Setup

Configure the Apollo client in `nuxt.config.ts`:

```ts
export default defineNuxtConfig({
graphql: {
clients: {
default: {
httpEndpoint: ''
}
}
}
})
```

## Plugin Customization

Create a plugin at `app/plugins/apollo.ts` to adjust the client at runtime:

```ts
export default defineNuxtPlugin(() => {
const { client } = useApolloClient()
const runtimeConfig = useRuntimeConfig()
const access = useCookie('accessToken')

const httpLink = new HttpLink({
uri: runtimeConfig.public.apiBase
})

const authLink = new SetContextLink((prevContext) => {
return {
headers: {
Authorization: `Bearer ${accessToken.value}`
}
}
})

const retryLink = new RetryLink()

const errorLink = new ErrorLink(({ error, forward, operation }) => {
console.log(error)
})


const cache = client.cache as InMemoryCache
Copy link

Copilot AI Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'possibleTypes' variable is used but never defined or imported in the code example. This will confuse readers trying to implement the solution. Consider adding an import statement or a comment explaining where this comes from.

Suggested change
const cache = client.cache as InMemoryCache
const cache = client.cache as InMemoryCache
// possibleTypes should be imported from your generated fragment types file
// e.g., import possibleTypes from '~/generated/possibleTypes'

Copilot uses AI. Check for mistakes.
cache.policies.addPossibleTypes(possibleTypes.possibleTypes)

const typePolicies: StrictTypedTypePolicies = {}
cache.policies.addTypePolicies(typePolicies)

client.setLink(ApolloLink.from([authLink, errorLink, retryLink, httpLink]))
})
```

### Plugin Execution Order

Nuxt runs plugins **in registration order**, based on file name sorting.
When customizing Apollo, ensure your plugin runs **before** any other plugin that uses Apollo Client.
You can control this by prefixing the file name (e.g., `00.apollo.ts`) or following [Nuxt’s plugin registration order](https://nuxt.com/docs/4.x/guide/directory-structure/app/plugins#registration-order).


## Best Practices

- Use `runtimeConfig` for environment-dependent URLs and secrets.
- Manage `possibleTypes` and `typePolicies` within plugins.
- Avoid storing tokens globally on the server.
- Test on both SSR and CSR modes for consistent behavior.
3 changes: 3 additions & 0 deletions packages/docs/nuxt/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ export default defineNuxtConfig({
})
```

> 💡 **Tip:** This setup works for most use cases.
> For advanced customization (e.g., runtime Apollo links, auth flow, or cache policies), see [Nuxt Custom Integration](/advance/nuxt-custom-integration).

Use anywhere in your app:

```ts
Expand Down
Loading