Feature Toggles

February 15, 2026 ยท View on GitHub

Lighthouse allows you to conditionally show or hide elements (fields, types, arguments or input fields) of your schema.

@show and @hide

The directives @show and @hide work in a similar way. Are logical opposites of each other.

For example, you might want to limit an experimental new field to test environments. @show is most suitable for this:

type Query {
  testInformation: String! @show(env: ["integration", "staging"])
}

Another example would be a field that should be available in every environment but production. In this case, @hide fits better:

type Query {
  debugInformation: String! @hide(env: ["production"])
}

@feature

The @feature directive allows to include fields, types, arguments, or input fields in the schema depending on whether a Laravel Pennant feature is active.

For example, you might want a new experimental field only to be available when the according feature is active:

type Query {
  experimentalField: String! @feature(name: "new-api")
}

In this case, experimentalField will only be included when the new-api feature is active.

Another example would be to only include a field when the feature is inactive:

type Query {
  deprecatedField: String! @feature(name: "new-api", when: "INACTIVE")
}

When using class based features, the fully qualified class name must be used as the value for the name argument:

type Query {
  experimentalField: String! @feature(name: "App\\Features\\NewApi")
}

Conditional Type Inclusion

When you conditionally include a type using @show, @hide or @feature, any fields using it must also be conditionally included. If the type is omitted but still used somewhere, the schema will be invalid.

type ExperimentalType @feature(name: "new-api") {
  field: String!
}

type Query {
  experimentalField: ExperimentalType @feature(name: "new-api")
}

Interaction With Schema Cache

@show and @hide work by manipulating the schema. This means that when using their env option, the inclusion or exclusion of elements depends on the value of app()->environment() at the time the schema is built and not update on later environment changes. If you are pre-generating your schema cache, make sure to match the environment to your deployment target.

The same goes for @feature. Whether a field is included in the schema will be based on the state of a feature at the time the schema is built. In addition, if you are pre-generating your schema cache, you will only be able to use features that support nullable scopes, as there won't be an authenticated user to check the feature against.