@scope directive, you can expose different schema variants to different clients from a single Viaduct instance.
Overview
Scopes enable you to:- Create public vs. internal API variants from the same codebase
- Hide implementation details and internal fields
- Support multi-tenant schema visibility
- Gradually roll out new features to specific clients
- Manage beta or experimental fields behind feature flags
Either nothing is scoped or everything has a scope applied to it. There is no default scope.
Common Use Cases
Within a typical deployment, you might expose:- A
viaductscope with a comprehensive schema available to all internal systems - A
viaduct:publicscope with a smaller schema available to frontend clients - A
viaduct:internal-toolsscope for admin dashboards and tooling
Basic Usage
The@scope directive is applied to types and fields to control visibility:
id,name, andemailare visible to bothviaductandviaduct:publicscopesinternalNotesandadminFlagsare only visible to theviaductscope
Type Extensions for Scope Control
Viaduct leverages GraphQL type extensions to separate fields within a type that belong to different scopes. This convention:- Avoids annotating each field individually
- Optimizes for human readability
- Clearly separates fields by intended audience
Example: Partial Field Exposure
If you want to expose only some fields from a type to a public API:Multiple Schemas
A single Viaduct instance can expose multiple schemas. Each schema is called a scope set and is identified by a schema ID. The schema seen by a request is controlled by theschemaId field of ExecutionInput:
Guidelines for @scope Annotation
Always Append @scope to the Main Type
When creating a new type (object, input, interface, union, or enum), always append@scope to the type itself:
@scope values.
Create Type Extensions for Narrower Scopes
If you need to limit visibility for certain fields, create a type extension and move those fields:Validation Rules
Viaduct performs static analysis at build time to ensure valid scope usage:1. Detecting Inaccessible Fields
The validator detects when fields reference types that aren’t accessible in the same scopes:- Adding
scope1orscope2to theListingtype’s scopes, OR - Adding
scope3to theUsertype’s scopes
2. Auto-Pruning Empty Types
When all fields of a type are out of scope, the type itself is pruned from the schema:listing-block scope, SpaceMetadata becomes empty (both bathroom and bedroom are unavailable), so the entire metadata field is pruned from StaySpace.
3. Validating Type Extension Scopes
Type extension scopes must be a subset of the original type’s scopes:Working with Interfaces and Unions
Interfaces
Unions
Define unions and their members in schema modules with proper dependency relationships:Example: Star Wars Demo
The Star Wars demo application uses two main scopes:default- Public schema for general availabilityextras- Extended schema with additional metadata
Best Practices
Do: Define Core Scopes
Establish a
default or public scope for general availability and use additional scopes for specialized access.Do: Keep Scopes Orthogonal
Avoid overlapping responsibilities between scopes to reduce confusion and accidental exposure.
Don't: Mix Scope Strategies
Either use scopes everywhere or nowhere. Partial adoption leads to confusion.
Don't: Rely Solely on Scopes
Scopes control schema visibility. Complement with application-level authorization for data-level controls.
Debugging Scope Issues
Verify Scope Configuration
Check what scopes are active in your request:Test with GraphQL Introspection
Use introspection queries to verify which fields are visible in different scopes:Common Error: Empty Type After Filtering
If you get unexpected null values, check if the type has been pruned due to all its fields being out of scope.See Also
Schema Reference
Learn about the @scope directive and other built-in directives
Field Classification
Understanding field visibility and classification