Graphql Client
Next-gql provides a wrapper around urql.
Define client query
// @/client/gql/queries-mutationsimport { gql } from '@urql/core';
export const MY_TASKS = gql`  query MyTasks {    me {      id      tasks {        id      }    }  }`;Setup cache for query objects.
Normalized cache is worth a read to understand why we define createTask and deleteTask mutation functions. TLDR: automatically add and remove entities from the cache. from the cache.
/* eslint-disable @typescript-eslint/no-explicit-any */'use client';
import { type MyTasksQuery, type Task } from '@/client/gql/generated/graphql';import schema from '@/client/gql/generated/schema.json';import { MY_TASKS } from '@/client/gql/queries-mutations';import {  createCacheExchange,  type Cache,  type CacheExchangeOptions,} from '@enalmada/next-gql/client/urql/cacheExchange';
const userDefinedConfig: CacheExchangeOptions = {  schema,  updates: {    Mutation: {      createTask(result: { createTask: Task }, _args: any, cache: Cache) {        cache.updateQuery({ query: MY_TASKS }, (data: MyTasksQuery | null) => {          if (result && data?.me?.tasks) {            const updatedTasks = [...data.me.tasks, result.createTask];            return { ...data, me: { ...data.me, tasks: updatedTasks } };          }          return data;        });      },      deleteTask(_result: any, args: { id: string }, cache: Cache) {        cache.updateQuery({ query: MY_TASKS }, (data: MyTasksQuery | null) => {          if (data?.me?.tasks) {            const updatedTasks = data.me.tasks.filter((task) => task.id !== args.id);            return { ...data, me: { ...data.me, tasks: updatedTasks } };          }          return data;        });      },    },  },};
export const cacheExchange = createCacheExchange(userDefinedConfig);Setup provider in layout (or any wrapper providing cookies, isLoggedIn status)
import React from 'react';import { cookies } from 'next/headers';import { UrqlWrapper as NextGqlProvider } from '@enalmada/next-gql/client/urql/UrqlWrapper';import { cacheExchange } from '@/client/gql/cacheExchange';
export async function Layout({ children }: { children: React.ReactNode }) {  const cookie = cookies().toString();  const url = process.env.URL + '/api/graphql';
  return (    <NextGqlProvider      url={url}      isLoggedIn={boolean}      cookie={cookie}      cacheExchange={cacheExchange}        >        {children}    </NextGqlProvider>  );}use queries
import { useQuery } from '@enalmada/next-gql';import { type MyTasksQuery, type Task } from '@/client/gql/generated/graphql';import { MY_TASKS } from '@/client/gql/queries-mutations';
const [{ data, error }] = useQuery<MyTasksQuery>({ query: MY_TASKS });Notes:
- types are kept in sync with codegen
 - it is important to have a root 
loading.tsxwhich provides a final fallback suspense. Without this, infinite querying can happen.