Source:
ocean/docs/adr/0040-graphql-schema-first-typescript.md| ✏️ Edit on GitHub
ADR-004: GraphQL Schema-First TypeScript Code Generation
Status
Accepted
Date
2025-07-29
Context
Our GraphQL implementation was using any types throughout the codebase, leading to:
- Type safety issues and runtime errors
- Poor developer experience with no IntelliSense
- Difficulty maintaining consistency between GraphQL schema and TypeScript types
- Manual type definitions that could drift from actual GraphQL responses
We needed a systematic approach to generate TypeScript types from our GraphQL schema to ensure type safety and maintainability.
Decision
We will implement a schema-first approach using GraphQL Code Generator to automatically generate TypeScript types from our GraphQL schema.
Implementation Details
-
GraphQL Code Generator Setup:
- Added
@graphql-codegen/cli,@graphql-codegen/typescript, and related packages - Created
codegen.tsconfiguration file - Added
pnpm run codegenscript for type generation
- Added
-
Schema Definition:
- Created
src/generated/schema.graphqlas single source of truth - Schema mirrors the GraphQL Yoga implementation in
supabase/functions/graphql-v2/index.ts - Includes proper scalar mappings (
JSON: Record<string, any>)
- Created
-
Type Generation:
- Generates
src/generated/graphql.tswith full TypeScript types - Creates
src/generated/introspection.jsonfor tooling - Uses Prettier for consistent formatting
- Generates
-
Type Transformation Layer:
- Created transformation functions to map GraphQL types to Database types
- Handles differences between GraphQL response structure and internal data models
- Ensures proper nullability handling (organizations always have member roles)
-
Integration Points:
- Updated all GraphQL hooks to use generated types
- Replaced
anytypes with proper GraphQL-generated interfaces - Added ESLint exception for generated files
Alternatives Considered
1. Manual Type Definitions
- Pros: Simple, no build step required
- Cons: Types can drift from schema, maintenance burden, no validation
2. Runtime Schema Introspection
- Pros: Always up-to-date with deployed schema
- Cons: Network dependency, slower development, build complexity
3. Code-First with TypeGraphQL
- Pros: Single source of truth in TypeScript
- Cons: Would require rewriting existing GraphQL Yoga server, migration complexity
Consequences
Positive
- Full Type Safety: All GraphQL operations are now fully typed
- Developer Experience: IntelliSense and compile-time error detection
- Maintainability: Schema changes automatically propagate to TypeScript types
- Consistency: Single source of truth prevents type drift
- Documentation: Generated types serve as living documentation
Negative
- Build Step Dependency: Requires running codegen when schema changes
- Complexity: Additional transformation layer needed for Database type compatibility
- Generated Code: Large generated files that shouldn't be manually edited
Neutral
- Learning Curve: Team needs to understand codegen workflow
- Tooling Setup: One-time configuration overhead
Implementation Notes
Type Transformation Pattern
// GraphQL types (generated)
import { Organization as GraphQLOrganization } from '@/generated/graphql'
// Database types (from Supabase)
import { Database } from '@/types/supabase'
// Transform function
function transformGraphQLOrganizationToDatabase(org: GraphQLOrganization): Organization {
return {
// Map GraphQL camelCase to Database snake_case
// Handle nullability differences
// Add computed fields
}
}
Development Workflow
- Update GraphQL schema in
src/generated/schema.graphql - Run
pnpm run codegento generate types - Update transformation functions if needed
- TypeScript compiler catches any breaking changes
Monitoring and Maintenance
- Schema Sync: Ensure generated schema stays in sync with GraphQL Yoga server
- Type Drift: Monitor for differences between GraphQL and Database types
- Performance: Generated types have minimal runtime impact
- Updates: Codegen packages should be updated regularly for latest features
Related Decisions
- ADR-001: GraphQL with Upstash Redis Caching
- ADR-002: Supabase JWT Authentication
- ADR-003: User UI vs Internal Monitoring Separation