
A Nuxt 3/4 module for making GraphQL requests with ease, leveraging the power of Nuxt's composables for doing amazing things.
useAsyncDataTGqlPulseClientKey type)graphql-request (graffle-compatible)useGqlPulseClient(clientName) — access raw clientuseGqlPulseRequest(...) — simple requestuseGqlPulseRawRequest(...) — low-level raw responseuseGqlPulseRequestWithCache(...) — sessionStorage cache (SPA)useAsyncGqlPulse(...) — SSR-friendly async datauseAsyncGqlPulseWithCache(...) — SPA async with sessionStorageuseGqlPulseBatchRequests(...) — batch multiple queriesuseAsyncGqlPulseBatch(...) — async batch with optional payload cacheInstall the module and peer deps:
npm install nuxt-gql-pulse graphql graphql-request
Add it to your nuxt.config.ts:
export default defineNuxtConfig({
modules: ['nuxt-gql-pulse'],
gqlPulse: {
clients: {
rickandmortyapi: {
endpoint: 'https://rickandmortyapi.com/graphql',
},
},
},
})
That’s it! You can now use Nuxt GQL Pulse in your Nuxt app ✨
<script setup lang="ts">
const query = /* GraphQL */ `
query {
characters(page: 1) {
results {
id
name
status
species
}
}
}
`
const { data } = await useAsyncGqlPulse<{
characters: {
results: { id: string; name: string; status: string; species: string }[]
}
}>({
client: 'rickandmortyapi',
document: query,
})
</script>
<template>
<div>
<h2>Rick & Morty Characters</h2>
<ul>
<li v-for="character in data.characters.results" :key="character.id">
{{ character.name }} — {{ character.status }} ({{ character.species }})
</li>
</ul>
</div>
</template>
Below is a practical comparison with relevant Nuxt GraphQL modules (research summary). This shows where features overlap and where nuxt-gql-pulse stands out.
| Capability / Module | nuxt-gql-pulse | nuxt-graphql-request | nuxt-graphql-client | nuxt-graphql-middleware | @nuxtjs/apollo / URQL |
|---|---|---|---|---|---|
| Multiple named clients | ✅ (built-in) | ✅ | ✅ | ⚠️ (server-focused) | ✅ |
Composables on useAsyncData | ✅ (ready) | ✅ (manual use) | ✅ (codegen) | ✅ (server wrappers) | ✅ |
| sessionStorage caching (client persistent) | ✅ unique | ❌ | ❌ | ❌ (in-memory/payload only) | ❌ (uses normalized cache) |
| Nuxt payload / SSR hydration cache | ✅ | ❌ | ⚠️ | ✅ | ✅ |
Integration with graphql-request / graffle | ✅ | ✅ | ⚠️ (may use different clients / codegen) | ⚠️ (server fetch) | ❌ (Apollo/URQL) |
Raw response (rawRequest) support | ✅ | ✅ | ⚠️ | ⚠️ | ✅ (client-specific) |
| Batch requests helper | ✅ | ⚠️ (manual) | ⚠️ | ⚠️ | ✅ (depends on client) |
| Nuxt 3 / 4 support | ✅ | ✅ | ✅ | ✅ | ✅ |
| Lightweight / minimal runtime footprint | ✅ | ✅ | ⚠️ (may add codegen) | ⚠️ | ❌ (Apollo larger) |
nuxt.config.ts)export default defineNuxtConfig({
modules: ['nuxt-gql-pulse'],
gqlPulse: {
/**
* Define your GraphQL clients
*/
clients: {
// 'rickandmortyapi' was used in examples above instead of 'default'
default: {
/**
* The client endpoint URL
*/
endpoint: 'https://rickandmortyapi.com/graphql',
/**
* Per-client request configuration
* Docs: https://github.com/graffle-js/graffle/blob/graphql-request/examples/configuration-fetch-options.ts
*/
options: {
method?: 'GET' | 'POST';
headers?: Headers | string[][] | Record<string, string> | (() => Headers | string[][] | Record<string, string>);
cache?: 'default' | 'force-cache' | 'no-cache' | 'no-store' | 'only-if-cached' | 'reload';
credentials?: 'include' | 'omit' | 'same-origin';
integrity?: string;
keepalive?: boolean;
mode?: 'same-origin' | 'cors' | 'navigate' | 'no-cors';
priority?: 'auto' | 'high' | 'low';
redirect?: 'error' | 'follow' | 'manual';
referrer?: string;
referrerPolicy?: '' | 'same-origin' | 'no-referrer' | 'no-referrer-when-downgrade' | 'origin' | 'origin-when-cross-origin' | 'strict-origin' | 'strict-origin-when-cross-origin' | 'unsafe-url';
errorPolicy?: 'none' | 'ignore' | 'all';
}
},
secondClient: {
// ... another client config
},
},
/**
* Global options applied to all clients
*/
options: {
// same structure as per-client `options`
},
/**
* Optional
* By default, all composables are auto-imported.
*
* You can exclude some if you only use one or two.
*
* Available auto-import composables:
* [
* 'useGqlPulseRequest',
* 'useGqlPulseRequestWithCache',
* 'useGqlPulseBatchRequests',
* 'useGqlPulseRawRequest',
* 'useAsyncGqlPulse',
* 'useAsyncGqlPulseWithCache',
* 'useAsyncGqlPulseBatch',
* ]
*
* ⚠️ `useGqlPulseClient` is **always** imported by default
* and cannot be excluded.
*/
excludeComposables: [],
},
})
🔑 Type Declarations (index.d.ts)
if you want to have type-safe client names in your project,
you can declare the TGqlPulseClientKey type globally in your project.
normally this is auto-generated in .nuxt/types/gql-pulse.d.ts during build,
but you can also declare it manually in your project for better DX.
declare global {
type TGqlPulseClientKey = 'rickandmortyapi'
}
export {}
🔧 API quick reference (signatures)
🔁 Caching: SSR vs SPA
useGqlPulseRequest
// Make standard GraphQL requests.
const data = await useGqlPulseRequest({
document, // string | DocumentNode
client: string, // defaults to first client
variables: TVariables,
})
useGqlPulseRawRequest
// Low-level request returning headers, status, and errors.
const res = await useGqlPulseRawRequest({
document: string,
client: string,
variables: TVariables,
}) // { status, headers, data, extensions, errors? }
useGqlPulseClient
// Access the underlying GraphQLClient instance.
// Always auto-imported and cannot be excluded.
const client = useGqlPulseClient('default')
useAsyncGqlPulse
// Nuxt-friendly async data fetching with optional payload cache. (SSR Friendly)
const { data, pending, error } = await useAsyncGqlPulse({
key: 'characters',
document,
variables,
client: 'default',
withPayloadCache: true,
})
useAsyncGqlPulseWithCache
// SPA-only sessionStorage caching.
const data = await useAsyncGqlPulseWithCache({
key: 'characters',
document,
variables,
})
useGqlPulseBatchRequests
// Batch multiple queries into one request.
const result = await useGqlPulseBatchRequests({
documents: [
{ document: query1, variables: { id: 1 } },
{ document: query2, variables: { id: 2 } },
],
client: 'default',
})
useAsyncGqlPulseBatch
// Nuxt-friendly async data fetching for batched requests with optional payload cache. (SSR Friendly)
const { data, pending, error } = await useAsyncGqlPulseBatch({
key: 'batch-1',
documents: [
{ document: query1, variables: { id: 1 } },
{ document: query2, variables: { id: 2 } },
],
client: 'default',
withPayloadCache: true,
})
useGqlPulseRequestWithCache
// SPA-only sessionStorage caching for single requests.
const result = await useGqlPulseRequestWithCache({
key: 'character-1',
document,
variables,
})
You can also provide custom configuration to clients via a Nuxt plugin:
export default defineNuxtPlugin(() => {
const client = useGqlPulseClient('rickandmortyapi')
const secondClient = useGqlPulseClient('secondClient')
/**
* Request middleware
* Runs before every GraphQL request.
* You can modify headers, body, or any request config here.
*/
const requestMiddleware = async (
request: RequestExtendedInit<Variables>
) => ({
...request,
headers: {
...request.headers,
Authorization: `Bearer token`,
},
})
/**
* Response middleware
* Runs after every GraphQL response.
* Perfect for custom logging or error handling.
*/
const responseMiddleware = async (
response: GraphQLClientResponse<unknown> | Error
) => {
if (response instanceof Error) {
console.error('❌ GraphQL error:', response.message)
} else {
console.log('✅ Response received:', response)
}
}
// Apply middlewares to both clients
for (const c of [client, secondClient]) {
c.requestConfig.requestMiddleware = requestMiddleware
c.requestConfig.responseMiddleware = responseMiddleware
}
/**
* Optional: override other requestConfig options
*/
// client.requestConfig.jsonSerializer = JSON
// client.requestConfig.body = JSON.stringify({ query: "{ characters { name } }" })
// client.requestConfig.signal = AbortSignal.timeout(5000)
// client.requestConfig.window = null
})
You can also provide Authentication headers in different ways:
nuxt.config.ts:export default defineNuxtConfig({
gqlPulse: {
clients: {
default: {
endpoint: 'https://default.com/graphql',
options: {
headers: {
authorization: 'Bearer TOKEN_HERE',
},
},
},
},
},
})
requestMiddleware in plugins/gqlPulse.ts:const client = useGqlPulseClient('default')
const requestMiddleware = async (request: RequestExtendedInit<Variables>) => {
const token = await getAuthTokenSomehow()
return {
...request,
headers: {
...request.headers,
authorization: `Bearer ${token}`,
},
}
}
client.requestConfig.requestMiddleware = requestMiddleware
useGqlPulseRequest options:const data = await useGqlPulseRequest({
document,
client: 'default',
variables,
requestOptions: {
headers: {
authorization: `Bearer ${token}`,
},
},
})
useGqlPulseClient():const client = useGqlPulseClient('rickandmortyapi')
// Replace all existing headers
client.setHeaders({
Authorization: 'Bearer my-secret-token',
'Content-Type': 'application/json',
})
// Set one header without touching the rest
client.setHeader('x-custom-header', 'my-value')
// Point the client to a different GraphQL endpoint
client.setEndpoint('https://custom-api.example.com/graphql')
See the examples directory for more usage examples:
gqlPulse.clientsclientName.options mirrors the request options available in graffle/graphql-request (headers, method, requestMiddleware, responseMiddleware, etc.). See graffle examples for advanced options and middleware.
See the graphql-request / graffle. for advanced request configuration and middleware examples.
This project builds on and integrates the excellent work of the GraphQL community:
This package itself is released under the MIT License.