Extensions are a way to enhance your schema, by adding typesafe client-only fields and specifying cache directives.

Custom fields


import { INDEX } from 'gqless'
export const Query = {
// Overwrite existing field
hello: 'world',
// or pass a function, to get the current value
hello: name => `hello ${name}`,
// Client-only properties can be
// any JS value
// query.doSomething(1) => 1
doSomething(test) {
return test
// Add new extensions to a given path
users: {
isQueryUsers: true, // query.users.isQueryUsers => true
[INDEX]: {
isAQueryUser: true, // query.users[0].isAQueryUser => true
// You can pass functions to extract
// the value at any time
me: me => ({
name: name => `${name} === ${me.name}`,
// Turn all Date scalars into Date objects
export const Date = date_string => new Date(date_string)

Keyed values

Keys are used to link different paths in the schema to the same value. The id field is used by default.


Lets say we previously fetched name on each of query.allUsers:

query.allUsers: [{ id: 0, name: 'a' }, { id: 1, name: 'b' }]

After fetching query.me, it will be returned from the cache:

query.me: { id: 0, name: 'a' }


Simply return a JSON serializable value unique per the given type:

import { GET_KEY } from 'gqless'
export const User = {
[GET_KEY]: user => user.username,

Cached redirects

Redirects let you first search for an existing value, before fetching from the network.


Let's say we previously loaded a list of users, query.users. There's a pretty good chance that given an ID, that User is already in the Cache.

Below will redirect calls from query.user({ id }), to a matching User (only if it exists).


Simply return a Value to have it linked up in the cache:

import { REDIRECT } from 'gqless'
export const Query = {
user: {
[REDIRECT](args, { match }) {
// pattern match against all User values
return match({ id: args.id })