A Roslyn-based C# Source Generator that scans GraphQL files for fragment definitions and produces matching C# types.
- Automatically generates C# types from GraphQL fragment definitions
- Schema-aware type inference for accurate field types
- Support for complex schema features (interfaces, unions, custom scalars)
- Preserves GraphQL scalar-to-C# type mappings
- Supports nullable reference types to reflect GraphQL nullability
- Handles nested selections with nested types
- Supports
@deprecated
directive with[Obsolete]
attributes - Handles fragment spreads through composition
- Configurable output (namespace, records vs classes, etc.)
- Comprehensive error reporting and diagnostics
Install the package from NuGet:
dotnet add package GraphQLSourceGen
Or add it directly to your project file:
<ItemGroup>
<PackageReference Include="GraphQLSourceGen" Version="1.0.0" />
</ItemGroup>
If you're developing or customising the generator, add a reference to the source generator project:
<ItemGroup>
<ProjectReference Include="..\GraphQLSourceGen\GraphQLSourceGen.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="true" />
</ItemGroup>
- Add
.graphql
files to your project with fragment definitions - Mark these files as
AdditionalFiles
in your project file:
<ItemGroup>
<AdditionalFiles Include="**\*.graphql" />
</ItemGroup>
- The source generator will automatically process these files and generate C# types for each fragment
You can configure the generator using MSBuild properties in your project file:
<PropertyGroup>
<!-- Basic configuration -->
<GraphQLSourceGenNamespace>MyCompany.GraphQL.Generated</GraphQLSourceGenNamespace>
<GraphQLSourceGenUseRecords>true</GraphQLSourceGenUseRecords>
<GraphQLSourceGenUseInitProperties>true</GraphQLSourceGenUseInitProperties>
<GraphQLSourceGenGenerateDocComments>true</GraphQLSourceGenGenerateDocComments>
<!-- Schema-aware configuration -->
<GraphQLSourceGenUseSchemaForTypeInference>true</GraphQLSourceGenUseSchemaForTypeInference>
<GraphQLSourceGenValidateNonNullableFields>true</GraphQLSourceGenValidateNonNullableFields>
<GraphQLSourceGenIncludeFieldDescriptions>true</GraphQLSourceGenIncludeFieldDescriptions>
<!-- Schema files (semicolon-separated list) -->
<GraphQLSourceGenSchemaFiles>schema.graphql;schema-extensions.graphql</GraphQLSourceGenSchemaFiles>
<!-- Custom scalar mappings (semicolon-separated list of name:type pairs) -->
<GraphQLSourceGenCustomScalarMappings>DateTime:System.DateTime;Upload:System.IO.Stream</GraphQLSourceGenCustomScalarMappings>
</PropertyGroup>
Schema-Aware Configuration Options
Option | Default | Description |
---|---|---|
GraphQLSourceGenUseSchemaForTypeInference | true | Enable schema-based type inference for more accurate types |
GraphQLSourceGenValidateNonNullableFields | true | Generate validation for non-nullable fields |
GraphQLSourceGenIncludeFieldDescriptions | true | Include field descriptions from schema in generated code |
GraphQLSourceGenSchemaFiles | "" | Semicolon-separated list of schema files to use for type inference |
GraphQLSourceGenCustomScalarMappings | "DateTime;Date;DateOnly;Time;TimeOnly" | Custom scalar type mappings |
By default, the generator adds XML documentation comments to the generated C# types. These comments provide:
-
Class-level documentation: Shows which GraphQL fragment and type the class was generated from
/// <summary> /// Generated from GraphQL fragment 'UserBasic' on type 'User' /// </summary>
-
Property-level documentation: Includes the original field name from the GraphQL schema
/// <summary> /// id /// </summary> public string? Id { get; init; }
These comments are automatically extracted from your GraphQL schema files during the build process. If your GraphQL schema includes descriptions for types and fields, those descriptions will also be included in the XML comments.
Benefits of XML documentation comments:
- Maintains the connection between your C# code and the GraphQL schema
- Provides IntelliSense documentation when using the generated types
- Can be used to generate API documentation
You can disable the generation of these comments using the GraphQLSourceGenGenerateDocComments
property as shown above.
fragment UserBasic on User {
id
name
email
isActive
}
Generated C# type:
using System;
using System.Collections.Generic;
#nullable enable
namespace GraphQL.Generated
{
/// <summary>
/// Generated from GraphQL fragment 'UserBasic' on type 'User'
/// </summary>
public record UserBasicFragment
{
/// <summary>
/// id
/// </summary>
public string? Id { get; init; }
/// <summary>
/// name
/// </summary>
public string? Name { get; init; }
/// <summary>
/// email
/// </summary>
public string? Email { get; init; }
/// <summary>
/// isActive
/// </summary>
public bool? IsActive { get; init; }
}
}
fragment UserWithProfile on User {
id
name
profile {
bio
avatarUrl
joinDate
}
}
fragment RequiredUserInfo on User {
id!
name!
email
}
fragment UserWithDeprecated on User {
id
name
username @deprecated(reason: "Use email instead")
oldField @deprecated
}
fragment UserWithPosts on User {
...UserBasic
posts {
id
title
}
}
The generator supports schema-aware type generation, which provides more accurate type information for your GraphQL fragments.
- Accurate Type Inference: The generator uses the schema to determine the exact type of each field, including nullability.
- Support for Complex Types: Properly handles interfaces, unions, custom scalars, and nested types.
- Type Validation: Validates that fields referenced in fragments actually exist in the schema.
- Better Documentation: Includes field descriptions from the schema in the generated code.
- Add your GraphQL schema files to your project
- Mark them as
AdditionalFiles
in your project file - Configure the schema files in your project file:
<PropertyGroup>
<GraphQLSourceGenSchemaFiles>schema.graphql;schema-extensions.graphql</GraphQLSourceGenSchemaFiles>
</PropertyGroup>
type User {
id: ID!
name: String!
email: String
isActive: Boolean
profile: UserProfile
posts: [Post!]
}
type UserProfile {
bio: String
avatarUrl: String
joinDate: DateTime
}
type Post {
id: ID!
title: String!
content: String
author: User!
}
scalar DateTime
fragment UserWithPosts on User {
id
name
email
profile {
bio
avatarUrl
joinDate
}
posts {
id
title
content
}
}
public record UserWithPostsFragment
{
public string Id { get; init; } // Non-nullable because ID! in schema
public string Name { get; init; } // Non-nullable because String! in schema
public string? Email { get; init; } // Nullable because String in schema
public ProfileModel? Profile { get; init; } // Nullable because UserProfile in schema
public List<PostModel> Posts { get; init; } // Non-nullable list because [Post!] in schema
public record ProfileModel
{
public string? Bio { get; init; }
public string? AvatarUrl { get; init; }
public DateTime? JoinDate { get; init; } // Mapped from DateTime scalar
}
public record PostModel
{
public string Id { get; init; }
public string Title { get; init; }
public string? Content { get; init; }
}
}
Common Patterns Custom Scalar Mappings Map GraphQL scalar types to specific C# types:
<PropertyGroup>
<GraphQLSourceGenCustomScalarMappings>
DateTime:System.DateTime;
Date:System.DateOnly;
Time:System.TimeOnly;
Upload:System.IO.Stream;
JSON:Newtonsoft.Json.Linq.JObject
</GraphQLSourceGenCustomScalarMappings>
</PropertyGroup>
For fragments on interface types, include the __typename field to enable proper type resolution:
fragment NodeFragment on Node {
__typename
id
... on User {
name
email
}
... on Post {
title
content
}
}
For fragments on union types, include the __typename field and use inline fragments:
fragment SearchResultFragment on SearchResult {
__typename
... on User {
id
name
}
... on Post {
id
title
}
}
Make sure:
- Your
.graphql
files are marked asAdditionalFiles
in your project file - Your GraphQL files contain valid fragment definitions
- You've added the package reference correctly
This indicates a syntax error in your GraphQL file. Check the error message for details on the specific issue.
The GraphQL file doesn't contain any fragment definitions. Make sure you're using the fragment Name on Type { ... }
syntax.
The specified schema file could not be found. Make sure:
- The file exists in your project
- The file is marked as an
AdditionalFile
- The path in
GraphQLSourceGenSchemaFiles
is correct (relative to your project)
The schema file contains syntax errors. Common issues include:
- Missing closing braces or parentheses
- Invalid type definitions
- Incorrect directive syntax
A fragment references a type that doesn't exist in the schema. Make sure:
- The type name in the fragment matches the type name in the schema
- The schema file includes all types used in your fragments
- Type names are case-sensitive
A fragment references a field that doesn't exist on the specified type. Make sure:
- The field name in the fragment matches the field name in the schema
- The field exists on the type specified in the fragment
- Field names are case-sensitive
If you have multiple schema files with conflicting type definitions:
- Merge the schemas: Combine the schema files into a single file
- Use schema extensions: Use the
extend type
syntax in GraphQL to extend existing types - Prioritize schemas: List the most important schema file first in
GraphQLSourceGenSchemaFiles
# Base schema
type User {
id: ID!
name: String!
}
# Extension schema
extend type User {
email: String
profile: UserProfile
}
If your schema contains circular references (e.g., User references Post, which references User):
- The generator handles circular references automatically
- For deep nesting, consider using fragment spreads instead of inline selections
- Use the @skip or @include directives to conditionally include fields
If you have conflicts with custom scalar mappings:
Ensure consistent scalar definitions across schema files Provide explicit mappings for all custom scalars Use domain-specific C# types for clarity
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.