Skip to content

GraphQLSP Config

@0no-co/graphqlsp is set up as a plugin in our TypeScript configuration:

tsconfig.json
{
"compilerOptions": {
"strict": true,
"plugins": [
{
"name": "@0no-co/graphqlsp",
"schema": "./schema.graphql",
"tadaOutputLocation": "./src/graphql-env.d.ts"
}
]
}
}

The name property, in tsconfig.json’s plugins list, referes directly to the package name of the plugin.

Apart from just, schema and tadaOutputLocation, @0no-co/graphqlsp accepts several configuration options that may be relevant in certain edge cases to disable some of its features.

Configuration Options

This section documents all of the provided configuration options for @0no-co/graphqlsp, explains their default settings, and how to further configure them.

schema

The schema option is the only required configuration option, and is used when the plugin starts up to load your GraphQL API’s schema. After the schema has been loaded, the provided schema is watched and reloaded whenever it changes.

The schema option currently allows for three different formats to load a schema. It accepts either:

  • a path to a .graphql file containing a schema definition (in GraphQL SDL format)
  • a path to a .json file containing a schema’s introspection query data
  • a URL to a GraphQL API that can be introspected
{
"compilerOptions": {
"plugins": [
{
"name": "@0no-co/graphqlsp",
"schema": "./schema.graphql"
}
]
}
}

Read more on how to configure the schema option, on the “Installation” page.

tadaOutputLocation

The tadaOutputLocation, when set, specifies the file or directory location to write an introspection type to, which gql.tada uses the plugin starts up to load your GraphQL API’s schema. After the schema has been loaded, the provided schema is watched and reloaded whenever it changes.

When the option only specifies a directory, a introspection.d.ts file will automatically be written to the output directory.

The tadaOutputLocation option accepts two different formats. Either a .d.ts file location, or a .ts file location. Depending on the file extension we specify, two different formats are used to save the introspection result:

Format 1 — .d.ts file

When writing a .d.ts file, @0no-co/graphqlsp will create a declaration file that automatically declares a setupSchema interface on gql.tada that, via declaration merging in TypeScript, configures gql.tada to use a schema project-wide for typings.

The resulting file will have the following shape:

graphql-env.d.ts
export type introspection = {
11 collapsed lines
"__schema": {
"queryType": {
"name": "Query"
},
"mutationType": null,
"subscriptionType": null,
"types": [
// ...
],
"directives": []
}
};
import * as gqlTada from 'gql.tada';
declare module 'gql.tada' {
interface setupSchema {
introspection: introspection
}
}

If we want to now customize scalars, for instance, we’ll need to create our own graphql() function by using the introspection type with gql.tada’s initGraphQLTada<>() function:

graphql.ts
import { initGraphQLTada } from 'gql.tada';
import type { introspection } from './graphql-env.d.ts';
export const graphql = initGraphQLTada<{
introspection: introspection;
scalars: {
DateTime: string,
JSON: any,
},
}>();

Read more on how to configure the tadaOutputLocation option, on the “Installation” page.

Format 2 — .ts file

When writing a .ts file instead, @0no-co/graphqlsp will create a regular TypeScript file that exports an introspection object, which is useful if we’re planning on re-using the introspection data during runtime.

The resulting file will have the following shape:

introspection.ts
const introspection = {
11 collapsed lines
"__schema": {
"queryType": {
"name": "Query"
},
"mutationType": null,
"subscriptionType": null,
"types": [
// ...
],
"directives": []
}
} as const;
export { introspection };

Hence, with this format it’s required to import the introspection and to create a graphql() function using the initGraphQLTada<>() function. The introspection type won’t be set up project-wide, since the .ts output from @0no-co/graphqlsp doesn’t contain a declare module declaration.

Read more on how to configure the tadaOutputLocation option, on the “Installation” page.

template

By default, @0no-co/graphqlsp will recognize any function named graphql() or gql() as containing GraphQL documents.

Customizing this option allows us to give these functions another name. For example, if we wanted to name a function parseGraphQL instead, we may set the option to "parseGraphQL".

{
"compilerOptions": {
"plugins": [
{
"name": "@0no-co/graphqlsp",
"schema": "./schema.graphql",
"template": "parseGraphQL"
}
]
}
}

templateIsCallExpression

By default, this option is true. When templateIsCallExpression: false is set, @0no-co/graphqlsp will instead look for tagged template literals.

trackFieldUsage

By default, this option is true.

When enabled, @0no-co/graphqlsp will track how you use the data of GraphQL documents and issue a warning when any fields in your selection sets aren’t actually used in your TypeScript code, so you can delete them.

import { FragmentOf, graphql, readFragment } from '../graphql';
export const PokemonItemFragment = graphql(`
fragment PokemonItem on Pokemon {
id
name
maxHP
}
`);
interface Props {
data: FragmentOf<typeof PokemonItemFragment>;
}
export const PokemonItem = ({ data }: Props) => {
const pokemon = readFragment(PokemonItemFragment, data);
return <li>{pokemon.name}</li>;
};

In the above example, we add a maxHP field to a fragment that the component’s code does not actually access, which causes a warning to be displayed.

shouldCheckForColocatedFragments

By default, this option is true.

When enabled, @0no-co/graphqlsp will scan imports for GraphQL fragments. When it finds an unused fragment in a file that’s imported in the current module, it issues a warning. This protects us from accidentally forgetting to reuse a fragment from an imported component file.

import { useQuery } from 'urql';
import { graphql } from '../graphql';
import { PokemonItem } from './PokemonItem';
const PokemonsQuery = graphql(`
query Pokemons ($limit: Int = 10) {
pokemons(limit: $limit) {
id
}
}
`, []);
export const PokemonList = () => {
const [result] = useQuery({ query: PokemonsQuery });
return null; // ...
};

In the above example, we add an import to a PokemonItem component. If the file contains a fragment that we have to use in our query a warning is displayed.