Skip to main content

Extending the GraphQL API

This guide explains how to add new queries, mutations, types, and permissions to the GraphQL API.

Architecture Overview​

The GraphQL implementation is split between two packages:

PackagePurpose
packages/shared-graphql/Schema definitions (.graphql files), generated types, authorization helpers
apps/web/src/lib/graphql/Resolvers, server configuration, Apollo Client

Adding a New Domain​

To add a new domain (e.g., project/):

1. Create the Schema​

Create packages/shared-graphql/src/schemas/project/schema.graphql with type definitions, inputs, responses, and query/mutation extensions.

2. Update Codegen Configuration​

Add the schema path to packages/shared-graphql/codegen.ts in the schema array.

3. Generate Types​

Run nx generate shared-graphql to regenerate TypeScript types.

4. Update Schema Loader​

Add the new schema to apps/web/src/lib/graphql/schema.ts.

5. Create Resolvers​

Create apps/web/src/lib/graphql/project/resolvers.ts with resolver implementations.

6. Register Resolvers​

Add resolvers to apps/web/src/lib/graphql/resolvers.ts.

Adding a New Type​

  1. Define TypeScript type in packages/shared-types/src/lib/core.ts
  2. Add GraphQL type to appropriate .graphql file in packages/shared-graphql/src/schemas/
  3. Run nx generate shared-graphql to regenerate types using GraphQL Code Generator
  4. Implement resolvers if needed

Adding a New Query​

  1. Add query definition to the appropriate .graphql schema file using extend type Query
  2. Run nx generate shared-graphql
  3. Implement resolver in the domain's resolvers.ts
  4. Register in main resolvers.ts

Adding a New Mutation​

  1. Add mutation definition to the appropriate .graphql schema file using extend type Mutation
  2. Run nx generate shared-graphql
  3. Implement resolver with input validation
  4. Register in main resolvers.ts

Adding a New OAuth Scope​

1. Update Scope Type​

Add the new slug to the Permission union in packages/shared-types/src/lib/core.ts, then create it in the WorkOS dashboard and attach it to the roles that should hold it (mirroring ROLE_PERMISSIONS).

2. Update Default Scopes (Optional)​

There is no default-grant list: a permission reaches a session only because WorkOS signed it into the access token. Keep slugs short — they ride in the session cookie.

3. Use in Resolvers​

Use requirePermission(context, "your:permission") in resolver implementations.

NX Commands​

CommandDescription
nx generate shared-graphqlGenerate TypeScript types from GraphQL schemas
nx build shared-graphqlBuild the shared-graphql package
nx lint shared-graphqlLint the shared-graphql package
nx test webTest the web app (includes GraphQL resolver tests)

Best Practices​

  1. Keep schemas in shared-graphql - Schema definitions should be in packages/shared-graphql/src/schemas/
  2. Use .graphql files - Keep schema definitions in .graphql files for better tooling
  3. Run generate after schema changes - Always run nx generate shared-graphql after modifying schemas
  4. Use response wrappers - Return { data, error } objects instead of throwing errors
  5. Validate inputs - Check all input fields and return clear error messages
  6. Authorize explicitly - Call requirePermission(); the @auth directive is documentation only
  7. Use database repositories - Put database logic in packages/shared-db, not resolvers

Reference Files​

FilePurpose
packages/shared-graphql/src/types.tsContext type and authorization helpers
packages/shared-graphql/codegen.tsCode generation configuration
apps/web/src/lib/graphql/schema.tsSchema loader
apps/web/src/lib/graphql/resolvers.tsCombined resolvers
apps/web/src/lib/graphql/common/utils.tsHelper functions