Versioning

Unlike REST APIs, GraphQL schemas do not use URL-based versioning (like /graphql/v2). Most schema changes are additive and non-breaking: adding new types and new fields does not affect existing queries. Removing a field or changing its nullability, however, is a breaking change.

GraphQL provides two directives to manage the lifecycle of schema elements:

  • @deprecated signals that a field is being phased out and consumers should migrate away.
  • @requiresOptIn signals that a field is not yet stable and requires explicit consumer consent.
GraphQL
type Query {
users: [User] @deprecated(reason: "Use the `authors` field instead")
authors: [User]
recommendations: [Book] @requiresOptIn(feature: "experimentalRecommendations")
}

Deprecation

You can deprecate output fields, input fields, arguments, and enum values. Deprecated elements remain functional but are flagged in introspection, warning consumers to migrate.

C#
// Types/BookQueries.cs
[QueryType]
public static partial class BookQueries
{
[GraphQLDeprecated("Use the `authors` field instead")]
public static User[] GetUsers()
{
// ...
}
public static User[] GetAuthors()
{
// ...
}
}

The .NET [Obsolete("reason")] attribute works the same way as [GraphQLDeprecated("reason")].

Warning: You cannot deprecate non-null arguments or input fields that have no default value. Deprecating a required field would silently break queries that depend on it.

Opt-In Features

While @deprecated marks fields that are going away, @requiresOptIn marks fields that are not yet stable. This is useful for rolling out experimental features, expensive operations, or anything where consumers should make a deliberate choice to use it.

Fields marked with @requiresOptIn are hidden from introspection by default. Consumers opt in by specifying the feature name.

Enabling Opt-In Features

Opt-in feature support is disabled by default. Enable it in your schema options:

C#
// Program.cs
builder
.AddGraphQL()
.ModifyOptions(o => o.EnableOptInFeatures = true);

Marking Fields as Opt-In

Apply @requiresOptIn to output fields, input fields, arguments, and enum values. The directive is repeatable, so a single field can require multiple features.

C#
// Types/Session.cs
public class Session
{
public string Id { get; set; }
public string Title { get; set; }
[RequiresOptIn("experimentalInstantApi")]
public Instant? StartInstant { get; set; }
[RequiresOptIn("experimentalInstantApi")]
public Instant? EndInstant { get; set; }
}

Warning: Like @deprecated, you cannot apply @requiresOptIn to non-null arguments or input fields without a default value. Hiding a required field would break queries.

Introspection

Consumers discover opt-in fields by passing the includeOptIn argument:

GraphQL
{
__type(name: "Session") {
fields(includeOptIn: ["experimentalInstantApi"]) {
name
requiresOptIn
}
}
}

The includeOptIn argument is available on fields, args, inputFields, and enumValues in introspection queries.

To discover all opt-in features in the schema:

GraphQL
{
__schema {
optInFeatures
}
}

Feature Stability

You can declare the stability level of each opt-in feature. This helps consumers understand whether a feature is experimental, preview, or has some other status.

C#
// Program.cs
builder
.AddGraphQL()
.ModifyOptions(o => o.EnableOptInFeatures = true)
.OptInFeatureStability("experimentalInstantApi", "experimental");

Consumers query feature stability through introspection:

GraphQL
{
__schema {
optInFeatureStability {
feature
stability
}
}
}

Next Steps

Last updated on April 13, 2026 by Michael Staib