Skip to content
Back to skills

Gql Guide

ASecurity

Interactive guide to soda-gql features and patterns

  • 42 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 31, 2026
developmenttypescriptgobashreactnextjsapisecuritydocumentation

Works with

  • cli
  • api

Security analysis

A100/100

Scanned May 31, 2026

npx -y skills add diegosouzapw/awesome-omni-skill --skill gql-guide --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Gql Guide?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Gql Guide
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/diegosouzapw-gql-guide/badge)](https://www.skillsdirectory.com/skills/diegosouzapw-gql-guide)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: gql:guide
description: Interactive guide to soda-gql features and patterns
user-invocable: true
argument-hint: [topic or question]
allowed-tools: Read, Grep, Glob, AskUserQuestion
---

# GraphQL Guide Skill

This skill provides interactive guidance on soda-gql features, syntax patterns, and best practices. Use `$ARGUMENTS` to route to specific topics, or ask the user to choose a topic.

## Topic Routing

Parse `$ARGUMENTS` to determine the user's intent, or use AskUserQuestion to offer topic selection.

### Available Topics

1. **tagged-template** — Tagged template syntax for fragments and operations
2. **fragment** — Fragment definitions and spreading patterns
3. **operation** — Query, mutation, and subscription operations
4. **union** — Union type handling and member selection
5. **directive** — GraphQL directives (@include, @skip, custom directives)
6. **metadata** — Fragment metadata and field-level callbacks
7. **setup** — Project setup, config, and initial codegen
8. **lsp** — LSP integration, editor setup, and diagnostics
9. **codegen** — Schema codegen, typegen, and build integration
10. **colocation** — Fragment colocation patterns ($colocate directive)

### Topic Selection

If `$ARGUMENTS` is empty or unclear, use AskUserQuestion:

**Question:** "What would you like guidance on?"
**Options:**
- "Tagged template syntax" → tagged-template
- "Fragment patterns" → fragment
- "Operations (queries/mutations)" → operation
- "Union types" → union
- "Directives" → directive
- "Metadata and callbacks" → metadata
- "Project setup" → setup
- "LSP and editor integration" → lsp
- "Codegen and build tools" → codegen
- "Fragment colocation" → colocation

## Topic Content

For each topic, provide:
1. Concept explanation
2. References to documentation files
3. Code examples from playground
4. Common patterns and anti-patterns
5. Related topics

---

## Topic 1: tagged-template

### Concept

soda-gql supports tagged template syntax for writing GraphQL fragments and operations. Only `gql` is exported from the generated runtime:

```typescript
import { gql } from "<outdir-path>"; // e.g. "@/graphql-system"

// Fragment with tagged template
const userFragment = gql.default(({ fragment }) =>
  fragment("UserFields", "User")`{
    id
    name
    email
  }`(),
);

// Operation with tagged template
const getUserQuery = gql.default(({ query }) =>
  query("GetUser")`($id: ID!) {
    user(id: $id) {
      id
      name
    }
  }`(),
);
```

### When to Use Tagged Template vs Callback Builder

**Decision Tree:**

1. **Fragment definition:**
   - ✅ Use tagged template: Simple field selection, no aliases
   - ❌ Use callback builder: Field aliases needed

2. **Fragment spreading (Fragment → Fragment):**
   - ✅ Use tagged template interpolation: `...${otherFragment}`

3. **Operation definition:**
   - ✅ Use tagged template: No fragment spreads via `.spread()`, no aliases, no $colocate
   - ❌ Use callback builder: Has fragment spreads via `.spread()`, aliases, or $colocate

4. **Special features:**
   - Metadata callbacks with variable access → callback builder only
   - Operations with `.spread()` → callback builder only

### Key Constraint

**Both tagged templates reject interpolation with values:**
- `fragment("Name", "Type")\`${value}\`` → ❌ Throws error
- `query("Name")\`{ field(id: ${id}) }\`` → ❌ Throws error

The only valid interpolation is fragment-to-fragment spreading: `fragment("Name", "Type")\`...${otherFragment} ...\``.

Operations with fragment spreads MUST use callback builder syntax with `.spread()` instead of tagged template interpolation.

### Documentation References

- **Callback-only features:** `playgrounds/vite-react/src/graphql/callback-builder-features.ts`
- **Fragment patterns:** `playgrounds/vite-react/src/graphql/fragment-spread-patterns.md`

### Code Examples

**Tagged template fragment:**
```typescript
// playgrounds/vite-react/src/graphql/fragments.ts
const userFields = gql.default(({ fragment }) =>
  fragment("UserFields", "User")`{
    id
    name
    email
    createdAt
  }`(),
);
```

**Tagged template operation (no spreads):**
```typescript
// playgrounds/vite-react/src/graphql/operations.ts
const simpleQuery = gql.default(({ query }) =>
  query("GetUsers")`{
    users {
      id
      name
    }
  }`(),
);
```

**Callback builder operation (with spreads):**
```typescript
// playgrounds/vite-react/src/graphql/callback-builder-features.ts
const userQuery = gql.default(({ query, $var }) =>
  query.operation({
    name: "GetUser",
    variables: {
      ...$var("id").ID("!"),
    },
    fields: ({ f, $ }) => ({
      ...f.user({ id: $.id })(({ f }) => ({
        ...userFields.spread(),
      })),
    }),
  }),
);
```

### Common Patterns

✅ **Simple fragment with tagged template:**
```typescript
const fields = gql.default(({ fragment }) =>
  fragment("UserBasic", "User")`{
    id
    name
    email
  }`(),
);
```

✅ **Fragment spreading another fragment (tagged template):**
```typescript
const extendedFields = gql.default(({ fragment }) =>
  fragment("ExtendedUser", "User")`{
    ...${userFields}
    createdAt
    updatedAt
  }`(),
);
```

❌ **Operation with fragment spread (WRONG - tagged template):**
```typescript
// This will FAIL - cannot use tagged template interpolation for fragment spreads in operations
const badQuery = gql.default(({ query }) =>
  query("BadQuery")`{
    user {
      ${userFields}
    }
  }`(),
);
```

✅ **Operation with fragment spread (CORRECT - callback builder):**
```typescript
const userQuery = gql.default(({ query, $var }) =>
  query.operation({
    name: "GetUser",
    variables: { ...$var("id").ID("!") },
    fields: ({ f, $ }) => ({
      ...f.user({ id: $.id })(({ f }) => ({
        ...userFields.spread(),
      })),
    }),
  }),
);
```

### Related Topics

- **fragment** — Fragment definition and spreading patterns
- **operation** — Operation structure and variable handling
- **metadata** — Callback-builder-only metadata feature

---

## Topic 2: fragment

### Concept

Fragments define reusable field selections with type safety. They can be spread into operations or composed into other fragments.

### Fragment Types

1. **Tagged template fragment** — Simple field selection
2. **Callback builder fragment** — Aliases, nested spreads, metadata
3. **Fragment spreading** — Composing fragments together

### Variable Declaration Pattern

**"Fragments declare requirements; operations declare contract"**

- Fragments can declare variables they need in the GraphQL definition
- Operations must explicitly declare ALL variables, including fragment requirements
- No auto-merge: operation variables are the source of truth

### Documentation References

- **Spread patterns:** `playgrounds/vite-react/src/graphql/fragment-spread-patterns.md`
- **Nested spreads:** `playgrounds/vite-react/src/graphql/nested-fragment-verification.ts`

### Code Examples

**Simple fragment:**
```typescript
const userBasic = gql.default(({ fragment }) =>
  fragment("UserBasic", "User")`{
    id
    name
    email
  }`(),
);
```

**Fragment with variables:**
```typescript
const userConditional = gql.default(({ fragment }) =>
  fragment("ConditionalUser", "User")`($includeEmail: Boolean!) {
    id
    name
    email @include(if: $includeEmail)
  }`(),
);
```

**Fragment spreading (Fragment → Fragment):**
```typescript
const userExtended = gql.default(({ fragment }) =>
  fragment("ExtendedUser", "User")`{
    ...${userBasic}
    createdAt
    updatedAt
  }`(),
);
```

**Operation spreading fragment (callback builder):**
```typescript
const getUserQuery = gql.default(({ query, $var }) =>
  query.operation({
    name: "GetUser",
    variables: {
      ...$var("id").ID("!"),
      ...$var("includeEmail").Boolean("!"),
    },
    fields: ({ f, $ }) => ({
      ...f.user({ id: $.id })(({ f }) => ({
        ...userConditional.spread({ includeEmail: $.includeEmail }),
      })),
    }),
  }),
);
```

### Common Patterns

✅ **Fragment composition via tagged template:**
```typescript
const baseFields = gql.default(({ fragment }) =>
  fragment("UserBase", "User")`{ id name }`(),
);
const extendedFields = gql.default(({ fragment }) =>
  fragment("UserExtended", "User")`{
    ...${baseFields}
    email
  }`(),
);
```

✅ **Operation declares all variables:**
```typescript
const getUserQuery = gql.default(({ query, $var }) =>
  query.operation({
    name: "GetUser",
    variables: {
      ...$var("id").ID("!"),
      ...$var("includeEmail").Boolean("!"), // ALL variables, including fragment requirements
    },
    fields: ({ f, $ }) => ({
      ...f.user({ id: $.id })(({ f }) => ({
        ...userConditional.spread({ includeEmail: $.includeEmail }),
      })),
    }),
  }),
);
```

❌ **Auto-merge expectation (WRONG):**
```typescript
// Fragment declares $includeEmail
const frag = gql.default(({ fragment }) =>
  fragment("F", "User")`($includeEmail: Boolean!) {
    id name email @include(if: $includeEmail)
  }`(),
);

// Operation does NOT auto-inherit variables — must declare includeEmail explicitly
const badQuery = gql.default(({ query, $var }) =>
  query.operation({
    name: "GetUser",
    variables: { ...$var("id").ID("!") }, // Missing includeEmail!
    fields: ({ f, $ }) => ({
      ...f.user({ id: $.id })(({ f }) => ({
        ...frag.spread(), // Will fail — $includeEmail not in scope
      })),
    }),
  }),
);
```

### Related Topics

- **tagged-template** — Syntax for fragment definitions
- **operation** — How operations use fragments
- **metadata** — Fragment-level metadata callbacks

---

## Topic 3: operation

### Concept

Operations define the GraphQL query/mutation/subscription structure with variables, arguments, and field selections.

### Operation Types

1. **Tagged template operation** — Simple operations without fragment spreads
2. **Callback builder operation** — Complex operations with spreads, aliases, $colocate

### Variable Handling

**Operations declare the contract:**
- All variables must be declared at operation level
- Fragment variables are NOT auto-merged
- In callback builder, use `$var("name").Type("!")` to declare variables

### Documentation References

- **Examples:** `playgrounds/vite-react/src/graphql/operations.ts`
- **Callback-only features:** `playgrounds/vite-react/src/graphql/callback-builder-features.ts`

### Code Examples

**Simple query (tagged template):**
```typescript
const getUsers = gql.default(({ query }) =>
  query("GetUsers")`{
    users {
      id
      name
    }
  }`(),
);
```

**Query with variables (tagged template):**
```typescript
const getUser = gql.default(({ query }) =>
  query("GetUser")`($id: ID!) {
    user(id: $id) {
      id
      name
      email
    }
  }`(),
);
```

**Query with fragment spread (callback builder):**
```typescript
const getUserWithFragment = gql.default(({ query, $var }) =>
  query.operation({
    name: "GetUserWithFragment",
    variables: {
      ...$var("id").ID("!"),
    },
    fields: ({ f, $ }) => ({
      ...f.user({ id: $.id })(({ f }) => ({
        ...userFields.spread(),
      })),
    }),
  }),
);
```

**Mutation (tagged template):**
```typescript
const createUser = gql.default(({ mutation }) =>
  mutation("CreateUser")`($input: CreateUserInput!) {
    createUser(input: $input) {
      id
      name
    }
  }`(),
);
```

### Common Patterns

✅ **Simple query (tagged template):**
```typescript
const getUserQuery = gql.default(({ query }) =>
  query("GetUser")`($id: ID!) {
    user(id: $id) {
      id
      name
      posts {
        id
        title
      }
    }
  }`(),
);
```

✅ **Operation with multiple variables (callback builder):**
```typescript
const getUserPosts = gql.default(({ query, $var }) =>
  query.operation({
    name: "GetUserPosts",
    variables: {
      ...$var("id").ID("!"),
      ...$var("limit").Int(),
      ...$var("offset").Int(),
    },
    fields: ({ f, $ }) => ({
      ...f.user({ id: $.id })(({ f }) => ({
        ...f.posts({ limit: $.limit, offset: $.offset })(({ f }) => ({
          id: f.id,
          title: f.title,
        })),
      })),
    }),
  }),
);
```

### Related Topics

- **tagged-template** — Operation syntax options
- **fragment** — Using fragments in operations
- **directive** — Adding directives to operations

---

## Topic 4: union

### Concept

Union types in GraphQL represent a value that could be one of several types. soda-gql handles union types using standard GraphQL inline fragment syntax in tagged templates.

### Union Member Selection

Union handling uses standard GraphQL inline fragment syntax (`... on TypeName { fields }`). Always include `__typename` for type discrimination:

```typescript
const searchQuery = gql.default(({ query }) =>
  query("Search")`($term: String!) {
    search(term: $term) {
      __typename
      ... on User {
        id
        name
      }
      ... on Organization {
        id
        name
        members
      }
    }
  }`(),
);
```

### Documentation References

- **Union verification:** `playgrounds/vite-react/src/graphql/union-type-verification.ts`
- **Callback-only features:** `playgrounds/vite-react/src/graphql/callback-builder-features.ts`

### Code Examples

**Union field selection (tagged template):**
```typescript
const searchQuery = gql.default(({ query }) =>
  query("Search")`($term: String!) {
    search(term: $term) {
      __typename
      ... on User {
        id
        name
        email
      }
      ... on Post {
        id
        title
        content
      }
    }
  }`(),
);
```

**Union with fragment spread (callback builder):**
```typescript
const userFields = gql.default(({ fragment }) =>
  fragment("UserFields", "User")`{ id name email }`(),
);
const postFields = gql.default(({ fragment }) =>
  fragment("PostFields", "Post")`{ id title content }`(),
);

const searchQuery = gql.default(({ query, $var }) =>
  query.operation({
    name: "Search",
    variables: { ...$var("term").String("!") },
    fields: ({ f, $ }) => ({
      ...f.search({ term: $.term })(({ f }) => ({
        __typename: f.__typename,
        ...userFields.spread(),
        ...postFields.spread(),
      })),
    }),
  }),
);
```

### Common Patterns

✅ **Always include __typename:**
```typescript
const q = gql.default(({ query }) =>
  query("Search")`($term: String!) {
    search(term: $term) {
      __typename
      ... on TypeA { id fieldA }
      ... on TypeB { id fieldB }
    }
  }`(),
);
```

✅ **Exhaustive member handling:**
```typescript
const q = gql.default(({ query }) =>
  query("SearchAll")`($term: String!) {
    search(term: $term) {
      __typename
      ... on User { id name }
      ... on Organization { id name }
      ... on Bot { id label }
    }
  }`(),
);
```

### Related Topics

- **fragment** — Using fragments with union members
- **metadata** — Type-specific metadata callbacks

---

## Topic 5: directive

### Concept

GraphQL directives modify field behavior (@include, @skip) or provide metadata for tools. soda-gql supports standard and custom directives.

### Directive Types

1. **Standard directives:** `@include(if: Boolean)`, `@skip(if: Boolean)`
2. **Custom directives:** Defined in schema, used for metadata or tooling

### Directive Syntax

**Tagged template with static values:**
```typescript
gql.default(({ fragment }) =>
  fragment("UserFields", "User")`{
    id
    name
    email @include(if: true)
  }`(),
);
```

**Tagged template with variables:**
```typescript
gql.default(({ fragment }) =>
  fragment("ConditionalUser", "User")`($includeEmail: Boolean!) {
    id
    name
    email @include(if: $includeEmail)
  }`(),
);
```

### Documentation References

- **Directive verification:** `playgrounds/vite-react/src/graphql/directive-verification.ts`

### Code Examples

**@include directive:**
```typescript
const conditionalFields = gql.default(({ fragment }) =>
  fragment("ConditionalUser", "User")`($showEmail: Boolean!) {
    id
    name
    email @include(if: $showEmail)
  }`(),
);
```

**@skip directive:**
```typescript
const fields = gql.default(({ fragment }) =>
  fragment("SkipEmail", "User")`($hideEmail: Boolean!) {
    id
    name
    email @skip(if: $hideEmail)
  }`(),
);
```

**Custom directive:**
```typescript
// Assuming schema has: directive @sensitive on FIELD_DEFINITION
const userFields = gql.default(({ fragment }) =>
  fragment("SensitiveUser", "User")`{
    id
    name
    socialSecurityNumber @sensitive
  }`(),
);
```

### Common Patterns

✅ **Conditional field inclusion (callback builder with fragment spread):**
```typescript
const detailsFragment = gql.default(({ fragment }) =>
  fragment("UserDetails", "User")`($includeDetails: Boolean!) {
    bio @include(if: $includeDetails)
    website @include(if: $includeDetails)
  }`(),
);

const getUserQuery = gql.default(({ query, $var }) =>
  query.operation({
    name: "GetUser",
    variables: {
      ...$var("id").ID("!"),
      ...$var("includeDetails").Boolean("!"),
    },
    fields: ({ f, $ }) => ({
      ...f.user({ id: $.id })(({ f }) => ({
        id: f.id,
        name: f.name,
        ...detailsFragment.spread({ includeDetails: $.includeDetails }),
      })),
    }),
  }),
);
```

### Related Topics

- **fragment** — Directives in fragment definitions
- **metadata** — Directive metadata for tooling

---

## Topic 6: metadata

### Concept

soda-gql allows attaching metadata to fragments and operations for build-time processing (e.g., component mapping, documentation generation). Metadata is passed as an argument to the template call.

### Metadata APIs

**Static metadata** — passed as argument to the template call:

```typescript
const frag = gql.default(({ fragment }) =>
  fragment("UserFields", "User")`{
    id
    name
  }`({
    metadata: { component: "UserCard" },
  }),
);
```

**Callback metadata** — receives variables for dynamic values:

```typescript
const frag = gql.default(({ fragment }) =>
  fragment("UserFields", "User")`($userId: ID!) {
    id
    name
  }`({
    metadata: ({ $ }: { $: { userId: string } }) => ({
      cacheKey: `user:${$.userId}`,
    }),
  }),
);
```

### Documentation References

- **Callback-only features:** `playgrounds/vite-react/src/graphql/callback-builder-features.ts`
- **Metadata verification:** `playgrounds/vite-react/src/graphql/metadata-verification.ts`

### Code Examples

**Static fragment metadata:**
```typescript
const userFragment = gql.default(({ fragment }) =>
  fragment("UserCard", "User")`{
    id
    name
    email
  }`({
    metadata: { component: "UserCard", description: "User profile data" },
  }),
);
```

**Callback metadata with variables:**
```typescript
const userFragment = gql.default(({ fragment }) =>
  fragment("CachedUser", "User")`($userId: ID!) {
    id
    name
    email
  }`({
    metadata: ({ $ }: { $: { userId: string } }) => ({
      cacheKey: `user:${$.userId}`,
    }),
  }),
);
```

**Callback builder operation with metadata:**
```typescript
const q = gql.default(({ query, $var }) =>
  query.operation({
    name: "GetUser",
    variables: { ...$var("id").ID("!") },
    metadata: ({ $, fragmentMetadata }) => ({
      entityId: $.id,
      fragmentCount: fragmentMetadata?.length ?? 0,
    }),
    fields: ({ f, $ }) => ({
      ...f.user({ id: $.id })(({ f }) => ({
        ...userFragment.spread(),
      })),
    }),
  }),
);
```

### Common Patterns

✅ **Component mapping:**
```typescript
gql.default(({ fragment }) =>
  fragment("UserProfile", "User")`{ id name }`({
    metadata: { component: "UserProfile" },
  }),
);
```

✅ **Dynamic cache key:**
```typescript
gql.default(({ fragment }) =>
  fragment("CachedUser", "User")`($id: ID!) { id name }`({
    metadata: ({ $ }: { $: { id: string } }) => ({
      cacheKey: `user:${$.id}`,
    }),
  }),
);
```

### Related Topics

- **fragment** — Metadata on fragments
- **colocation** — $colocate with metadata

---

## Topic 7: setup

### Concept

Setting up a new soda-gql project involves config file creation, schema setup, and initial codegen.

### Setup Steps

1. **Install dependencies:**
   ```bash
   bun add @soda-gql/core @soda-gql/builder
   bun add -d @soda-gql/cli
   ```

2. **Add framework plugin (optional but recommended):**
   ```bash
   # For Vite
   bun add -d @soda-gql/vite-plugin
   # For Next.js
   bun add -d @soda-gql/next-plugin
   ```

3. **Create config file (`soda-gql.config.ts`):**
   ```typescript
   import { defineConfig } from '@soda-gql/config';

   export default defineConfig({
     outdir: './src/graphql/generated',
     schemas: {
       default: {
         schemaFiles: ['./schema.graphql'],
       },
     },
   });
   ```

4. **Run initial codegen:**
   ```bash
   bun run soda-gql codegen schema
   ```

5. **Configure build plugin (Vite example):**
   ```typescript
   // vite.config.ts
   import { sodaGql } from '@soda-gql/vite-plugin';

   export default {
     plugins: [sodaGql()],
   };
   ```

### Documentation References

- **Main README:** `README.md` — Installation and quick start
- **Playground examples:** `playgrounds/vite-react/src/graphql/` — Working examples of all features

### Common Issues

**Issue: codegen fails with "config not found"**
- Check config file is named correctly: `soda-gql.config.{ts,js,mjs}`
- Check config exports with `export default`

**Issue: "Cannot find module '@soda-gql/core'"**
- Run `bun install` to install dependencies
- Check package.json includes @soda-gql packages

**Issue: Types not updating in editor**
- Restart TypeScript server
- Check outdir matches tsconfig include paths

### Related Topics

- **codegen** — Running codegen and typegen
- **lsp** — Editor integration

---

## Topic 8: lsp

### Concept

soda-gql provides LSP (Language Server Protocol) integration for real-time diagnostics, autocomplete, and hover information in editors.

### LSP Features

1. **Real-time diagnostics:** Type errors, invalid fields, syntax errors
2. **Autocomplete:** Field names, types, directives
3. **Hover information:** Type info, documentation
4. **Go to definition:** Jump to schema type definitions

### Editor Setup

**VS Code:**
1. Install LSP extension (if available)
2. Configure workspace settings:
   ```json
   {
     "soda-gql.configPath": "./soda-gql.config.ts"
   }
   ```

**Other editors:**
- Use language server client compatible with your editor
- Point to soda-gql LSP server

### LSP Diagnostics

The LSP validates:
- Field existence on types
- Argument types and required args
- Fragment type compatibility
- Variable types
- Directive usage

### Common Issues

**Issue: LSP not providing diagnostics**
- Check config file is found (`found: true` in project detection)
- Restart editor/LSP server
- Check LSP logs for errors

**Issue: False positive errors**
- Run `bun run soda-gql codegen schema` to sync generated types
- Check schema files are up to date

### Related Topics

- **setup** — Initial LSP configuration
- **codegen** — Keeping LSP in sync with schema

---

## Topic 9: codegen

### Concept

soda-gql codegen generates TypeScript types from GraphQL schemas (schema codegen) and validates/generates types from tagged templates (typegen).

### Codegen Commands

1. **Schema codegen:**
   ```bash
   bun run soda-gql codegen schema
   ```
   - Reads schema files from config
   - Generates runtime type system in outdir
   - Creates fragment and query builder types

2. **Type generation (typegen):**
   ```bash
   bun run soda-gql typegen
   ```
   - Scans codebase for tagged templates
   - Validates field selections against schema
   - Generates TypeScript types for fragments/operations

### Build Integration

**Development workflow:**
1. Edit schema files
2. Run `bun run soda-gql codegen schema`
3. Edit fragments/operations
4. Build plugin auto-runs typegen during build

**Watch mode (if supported):**
```bash
bun run soda-gql codegen schema --watch
```

### Documentation References

- **Monorepo infrastructure:** `docs/guides/monorepo-infrastructure.md` — Build system

### Common Issues

**Issue: "Schema file not found"**
- Check schemaFiles paths in config are relative to config file
- Use Read tool to verify file exists at expected path

**Issue: Typegen shows "unknown field"**
- Run schema codegen first: `bun run soda-gql codegen schema`
- Check field name spelling matches schema

**Issue: Generated types not updating**
- Delete generated directory and re-run codegen
- Check outdir in config matches import paths

### Related Topics

- **setup** — Initial codegen configuration
- **lsp** — Real-time validation vs build-time codegen

---

## Topic 10: colocation

### Concept

Fragment colocation places fragment definitions near the components that use them, improving code organization and enabling build-time optimizations.

### Colocation Patterns

**$colocate in callback builder spread:**
```typescript
const userQuery = gql.default(({ query, $var }) =>
  query.operation({
    name: "GetUser",
    variables: { ...$var("id").ID("!") },
    fields: ({ f, $ }) => ({
      ...f.user({ id: $.id })(({ f }) => ({
        id: f.id,
        ...userFragment.spread({ $colocate: true }),
      })),
    }),
  }),
);
```

**Component colocation:**
```typescript
// UserCard.tsx
export const userCardFragment = gql.default(({ fragment }) =>
  fragment("UserCardFields", "User")`{
    id
    name
    email
    avatarUrl
  }`(),
);

export function UserCard({ user }) {
  // Component uses fragment data
}
```

### Build-Time Processing

Colocation enables:
- Dead code elimination (unused fragments removed)
- Component-fragment association tracking
- Automatic fragment composition

### Documentation References

- **Callback-only features:** `playgrounds/vite-react/src/graphql/callback-builder-features.ts` — $colocate examples

### Common Patterns

✅ **Component-fragment pair:**
```typescript
// UserProfile.tsx
const userProfileFragment = gql.default(({ fragment }) =>
  fragment("UserProfile", "User")`{
    id
    name
    email
    bio
  }`(),
);

function UserProfile({ data }) {
  // Use fragment data
}
```

✅ **Fragment composition with colocation:**
```typescript
const parentQuery = gql.default(({ query, $var }) =>
  query.operation({
    name: "GetUserPage",
    variables: { ...$var("id").ID("!") },
    fields: ({ f, $ }) => ({
      ...f.user({ id: $.id })(({ f }) => ({
        ...profileFragment.spread({ $colocate: true }),
        ...settingsFragment.spread({ $colocate: true }),
      })),
    }),
  }),
);
```

### Related Topics

- **fragment** — Fragment spreading and composition
- **metadata** — Component metadata with colocation

---

## Interactive Mode

If the user's question doesn't match a specific topic, use Grep to search documentation:

1. Extract keywords from user's question
2. Use Grep to search docs/guides/ and playgrounds/
3. Read matching files and synthesize answer
4. Reference specific documentation sections

### Example: User asks "How do I add pagination?"

1. Grep for "pagination" in docs and playground
2. If not found, explain general approach:
   - Add limit/offset arguments to field
   - Use variables in operation
   - Show example with args
3. Suggest related topics: operation, fragment

## Validation Checklist

Before completing this skill, ensure:
- ✅ Topic was identified from $ARGUMENTS or user selection
- ✅ Relevant documentation was referenced
- ✅ Code examples were provided from playground or synthesized
- ✅ Common patterns and anti-patterns were shown
- ✅ Related topics were suggested for further exploration

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…