|
| 1 | +# Custom Apollo Integration for Nuxt |
| 2 | + |
| 3 | + |
| 4 | +A compact guide for setting up and extending Apollo Client in Nuxt, focusing on module limitations, plugin customization, and best practices. |
| 5 | + |
| 6 | +## Overview |
| 7 | + |
| 8 | +Nuxt modules simplify setup but run only at **build time**, meaning they can’t access runtime APIs like `useRuntimeConfig` or `useApolloClient`. |
| 9 | +For dynamic logic (auth, caching, token refresh), use **plugins**, which run after app startup with full Nuxt context. |
| 10 | + |
| 11 | +## Why Use Plugins |
| 12 | + |
| 13 | +### 1. Serialization |
| 14 | +During build, Nuxt serializes module options into JSON. |
| 15 | +Complex objects like `ApolloClient` or custom `Link`s **lose references** and can’t be reused at runtime. |
| 16 | + |
| 17 | +### 2. Context Isolation |
| 18 | +Modules execute in a **separate build context**, isolated from Nuxt’s runtime environment. |
| 19 | +Plugins, on the other hand, run inside the live app, where you can modify the Apollo client safely. |
| 20 | + |
| 21 | +✅ **Modules:** define static config & generate runtime code |
| 22 | +✅ **Plugins:** handle runtime logic & modify live instances |
| 23 | + |
| 24 | +## Basic Setup |
| 25 | + |
| 26 | +Configure the Apollo client in `nuxt.config.ts`: |
| 27 | + |
| 28 | +```ts |
| 29 | +export default defineNuxtConfig({ |
| 30 | + graphql: { |
| 31 | + clients: { |
| 32 | + default: { |
| 33 | + httpEndpoint: '' |
| 34 | + } |
| 35 | + } |
| 36 | + } |
| 37 | +}) |
| 38 | +``` |
| 39 | + |
| 40 | +## Plugin Customization |
| 41 | + |
| 42 | +Create a plugin at `app/plugins/apollo.ts` to adjust the client at runtime: |
| 43 | + |
| 44 | +```ts |
| 45 | +export default defineNuxtPlugin(() => { |
| 46 | + const { client } = useApolloClient() |
| 47 | + const runtimeConfig = useRuntimeConfig() |
| 48 | + const access = useCookie('accessToken') |
| 49 | + |
| 50 | + const httpLink = new HttpLink({ |
| 51 | + uri: runtimeConfig.public.apiBase |
| 52 | + }) |
| 53 | + |
| 54 | + const authLink = new SetContextLink((prevContext) => { |
| 55 | + return { |
| 56 | + headers: { |
| 57 | + Authorization: `Bearer ${accessToken.value}` |
| 58 | + } |
| 59 | + } |
| 60 | + }) |
| 61 | + |
| 62 | + const retryLink = new RetryLink() |
| 63 | + |
| 64 | + const errorLink = new ErrorLink(({ error, forward, operation }) => { |
| 65 | + console.log(error) |
| 66 | + }) |
| 67 | + |
| 68 | + |
| 69 | + const cache = client.cache as InMemoryCache |
| 70 | + cache.policies.addPossibleTypes(possibleTypes.possibleTypes) |
| 71 | + |
| 72 | + const typePolicies: StrictTypedTypePolicies = {} |
| 73 | + cache.policies.addTypePolicies(typePolicies) |
| 74 | + |
| 75 | + client.setLink(ApolloLink.from([authLink, errorLink, retryLink, httpLink])) |
| 76 | +}) |
| 77 | +``` |
| 78 | + |
| 79 | +### Plugin Execution Order |
| 80 | + |
| 81 | +Nuxt runs plugins **in registration order**, based on file name sorting. |
| 82 | +When customizing Apollo, ensure your plugin runs **before** any other plugin that uses Apollo Client. |
| 83 | +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). |
| 84 | + |
| 85 | + |
| 86 | +## Best Practices |
| 87 | + |
| 88 | +- Use `runtimeConfig` for environment-dependent URLs and secrets. |
| 89 | +- Manage `possibleTypes` and `typePolicies` within plugins. |
| 90 | +- Avoid storing tokens globally on the server. |
| 91 | +- Test on both SSR and CSR modes for consistent behavior. |
0 commit comments