Fix: gql.tada Not Working — Types Not Inferred, Schema Not Found, or IDE Not Showing Completions
Quick Answer
How to fix gql.tada issues — schema introspection, type-safe GraphQL queries, fragment masking, urql and Apollo Client integration, IDE setup, and CI type checking.
The Problem
graphql() returns unknown instead of typed data:
import { graphql } from 'gql.tada';
const UserQuery = graphql(`
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`);
// TypeScript shows the result type as unknown — no inferenceOr the IDE shows no autocompletion inside the template literal:
const query = graphql(`
query {
| // No suggestions after typing
}
`);Or the schema file can’t be found:
Error: Could not find schema — or —
gql.tada: No schema found in tsconfig.jsonWhy This Happens
gql.tada infers GraphQL types at the TypeScript level — no codegen step needed. But it requires specific configuration:
- The GraphQL schema must be available to TypeScript — gql.tada reads a schema file (introspection JSON or SDL) referenced in
tsconfig.json. Without this, it can’t infer field types from queries. - The TypeScript plugin must be configured — gql.tada uses a TypeScript language service plugin for IDE autocompletion. Without the plugin in
tsconfig.json, the IDE doesn’t know about the GraphQL schema. - Schema must be up to date — gql.tada reads the schema at build/typecheck time. If the API changed but the local schema file is outdated, types don’t match reality.
- Template literal types have limits — TypeScript’s template literal inference works with
graphql()from gql.tada’s specific import. Using a differentgraphqltag or wrapping it in another function breaks inference.
Fix 1: Setup and Schema Introspection
npm install gql.tada
npm install -D @0no-co/graphqlsp # TypeScript LSP plugin for IDE support# Generate introspection schema from your GraphQL API
npx gql.tada generate-schema "http://localhost:4000/graphql" --output schema.graphql
# Or from a file
npx gql.tada generate-schema ./schema.graphql --output introspection.ts
# Generate the output file used by TypeScript
npx gql.tada generate-output --tsconfig ./tsconfig.json// tsconfig.json — configure the TypeScript plugin
{
"compilerOptions": {
"strict": true,
"plugins": [
{
"name": "@0no-co/graphqlsp",
"schema": "./schema.graphql",
"tadaOutputLocation": "./src/graphql-env.d.ts"
}
]
}
}// src/graphql/tada.ts — initialize gql.tada
import { initGraphQLTada } from 'gql.tada';
import type { introspection } from '../graphql-env';
export const graphql = initGraphQLTada<{
introspection: introspection;
scalars: {
DateTime: string;
JSON: Record<string, unknown>;
};
}>();
export type { FragmentOf, ResultOf, VariablesOf } from 'gql.tada';
export { readFragment } from 'gql.tada';Fix 2: Type-Safe Queries
import { graphql, type ResultOf, type VariablesOf } from '@/graphql/tada';
// Query — types are inferred from the schema
const GetUsersQuery = graphql(`
query GetUsers($limit: Int, $offset: Int) {
users(limit: $limit, offset: $offset) {
id
name
email
role
createdAt
posts {
id
title
}
}
}
`);
// ResultOf<typeof GetUsersQuery> = {
// users: {
// id: string;
// name: string;
// email: string;
// role: string;
// createdAt: string;
// posts: { id: string; title: string }[];
// }[];
// }
// VariablesOf<typeof GetUsersQuery> = {
// limit?: number | null;
// offset?: number | null;
// }
// Mutation
const CreateUserMutation = graphql(`
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
id
name
email
}
}
`);
// Variables are type-checked
type CreateUserVars = VariablesOf<typeof CreateUserMutation>;
// { input: { name: string; email: string; role?: string } }Fix 3: Fragments
import { graphql, readFragment, type FragmentOf } from '@/graphql/tada';
// Define a fragment
const UserFragment = graphql(`
fragment UserFields on User {
id
name
email
avatar
}
`);
// Use fragment in a query
const GetUserQuery = graphql(`
query GetUser($id: ID!) {
user(id: $id) {
...UserFields
posts {
id
title
}
}
}
`, [UserFragment]); // Pass fragments as second argument
// Component that accepts fragment data
function UserCard({ user }: { user: FragmentOf<typeof UserFragment> }) {
// readFragment unmasks the fragment data
const data = readFragment(UserFragment, user);
// data = { id: string, name: string, email: string, avatar: string }
return (
<div>
<img src={data.avatar} alt={data.name} />
<h3>{data.name}</h3>
<p>{data.email}</p>
</div>
);
}
// Nested fragments
const PostFragment = graphql(`
fragment PostFields on Post {
id
title
body
author {
...UserFields
}
}
`, [UserFragment]);Fix 4: urql Integration
npm install urql gql.tada'use client';
import { useQuery, useMutation } from 'urql';
import { graphql, type ResultOf } from '@/graphql/tada';
const PostsQuery = graphql(`
query Posts($limit: Int!) {
posts(limit: $limit) {
id
title
excerpt
author {
name
}
}
}
`);
function PostList() {
const [result] = useQuery({
query: PostsQuery,
variables: { limit: 10 },
// Variables are type-checked automatically
});
if (result.fetching) return <div>Loading...</div>;
if (result.error) return <div>Error: {result.error.message}</div>;
// result.data is fully typed
return (
<ul>
{result.data?.posts.map(post => (
<li key={post.id}>
<h3>{post.title}</h3>
<p>{post.excerpt}</p>
<span>by {post.author.name}</span>
</li>
))}
</ul>
);
}
// Mutation
const CreatePostMutation = graphql(`
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
id
title
}
}
`);
function CreatePostForm() {
const [, createPost] = useMutation(CreatePostMutation);
async function handleSubmit(data: { title: string; body: string }) {
const result = await createPost({
input: data, // Type-checked against CreatePostInput
});
if (result.data) {
console.log('Created:', result.data.createPost.id);
}
}
return <form onSubmit={/* ... */}>...</form>;
}Fix 5: Apollo Client Integration
import { useQuery, useMutation } from '@apollo/client';
import { graphql, type ResultOf, type VariablesOf } from '@/graphql/tada';
const GetUserQuery = graphql(`
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`);
function UserProfile({ userId }: { userId: string }) {
const { data, loading, error } = useQuery(GetUserQuery, {
variables: { id: userId },
});
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
// data is typed as ResultOf<typeof GetUserQuery>
return (
<div>
<h1>{data?.user?.name}</h1>
<p>{data?.user?.email}</p>
</div>
);
}Fix 6: CI/CD Schema Validation
// package.json
{
"scripts": {
"schema:update": "gql.tada generate-schema http://localhost:4000/graphql --output schema.graphql",
"graphql:generate": "gql.tada generate-output --tsconfig ./tsconfig.json",
"graphql:check": "gql.tada check --tsconfig ./tsconfig.json",
"predev": "npm run graphql:generate",
"prebuild": "npm run graphql:generate"
}
}# .github/workflows/graphql-check.yml
name: GraphQL Type Check
on: [pull_request]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm ci
- run: npx gql.tada generate-output
- run: npx tsc --noEmit # Type-check all queries against schemaStill Not Working?
Types are unknown — no inference — the schema isn’t configured. Check tsconfig.json has the @0no-co/graphqlsp plugin with the correct schema path. Run npx gql.tada generate-output to create the graphql-env.d.ts file. Ensure you import graphql from your initialized tada.ts, not from gql.tada directly.
No autocompletion in the IDE — VS Code must use the workspace TypeScript version. Open Command Palette → “TypeScript: Select TypeScript Version” → “Use Workspace Version”. The @0no-co/graphqlsp plugin only runs with the workspace TS.
Schema is outdated — run npx gql.tada generate-schema <url> to re-download the schema. The introspection result reflects the API at download time. Add schema:update to your CI or pre-dev scripts.
Fragment types don’t propagate — fragments must be passed as the second argument to graphql(): graphql(\query { …UserFields }`, [UserFragment])`. Without this, gql.tada can’t resolve fragment spreads and the fields are missing from the result type.
For related GraphQL issues, see Fix: GraphQL Yoga Not Working and Fix: Pothos Not Working.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: cmdk Not Working — Command Palette Not Opening, Items Not Filtering, or Keyboard Navigation Broken
How to fix cmdk command palette issues — Dialog setup, custom filtering, groups and separators, keyboard shortcuts, async search, nested pages, and integration with shadcn/ui and Tailwind.
Fix: Conform Not Working — Form Validation Not Triggering, Server Errors Missing, or Zod Schema Rejected
How to fix Conform form validation issues — useForm setup with Zod, server action integration, nested and array fields, file uploads, progressive enhancement, and Remix and Next.js usage.
Fix: CodeMirror Not Working — Editor Not Rendering, Extensions Not Loading, or React State Out of Sync
How to fix CodeMirror 6 issues — basic setup, language and theme extensions, React integration, vim mode, collaborative editing, custom keybindings, and read-only mode.
Fix: GraphQL Yoga Not Working — Schema Errors, Resolvers Not Executing, or Subscriptions Failing
How to fix GraphQL Yoga issues — schema definition, resolver patterns, context and authentication, file uploads, subscriptions with SSE, error handling, and Next.js integration.