GraphQL Schema Contracts | Cosmo by WunderGraph - WunderGraph
One source graph. Multiple tailored APIs. No duplicate maintenance.
Tag fields with @tag directives and create filtered contract views for each audience. Sensitive fields stay out of public APIs. Contracts stay in sync automatically when the source changes.
One source graph. Multiple filtered contracts.
The problem
Why serving multiple audiences from one graph is hard
As federated graphs grow, they serve more audiences with more access requirements. Without proper tooling, teams either expose too much or maintain duplicate graphs.
Exposing internal fields to external consumers is a security risk
A federated graph grows to include fields your internal tools rely on — user IDs, admin flags, sensitive data. Without explicit filtering, public consumers may be able to see fields that were only meant for internal teams.
Maintaining separate graphs for different audiences is a maintenance nightmare
One graph for internal teams. One for partners. One for public consumers. Each one drifts. Changes made to the source require manual updates to every copy. The maintenance cost compounds as the graph grows.
Different consumers need different views of the same graph
Partners may need specific fields based on integration agreements. Legacy consumers may need the old schema shape during migration. Public APIs may need to exclude internal or sensitive fields. Without schema contracts, teams usually duplicate graphs or expose more than they should.
Our solution
Tag once. Serve multiple audience-specific schemas.
Schema Contracts let you annotate your source graph with @tag directives and create filtered views that exclude tagged elements. Each contract gets its own router deployment, client schema, analytics, and persisted operations. The source graph remains the single source of truth, and contracts stay in sync automatically.
How it works end to end
- Annotate schema elements with
@tagdirectives — on objects, interfaces, inputs, types, and fields. - Create a contract with
wgc contract create, specifying which tags to exclude. - The control plane generates two schemas: a router schema for query planning and a client schema for introspection.
- A contract router deployment serves the tailored API to its audience. Each contract has its own router deployment with independent analytics.
- When the source graph changes, contracts recompose automatically — no manual sync needed.
Before & After
| Before Cosmo | With Cosmo |
|---|---|
| Duplicate graphs for different audiences | Single source graph with filtered contracts |
| Manual schema maintenance across versions | Automatic synchronization on source changes |
| Risk of exposing sensitive fields | Explicit tag-based filtering |
| Complex multi-graph deployment | Separate router deployments for each contract |
How filtering works
Two schemas per contract
- Router schema — used internally for query planning; includes @inaccessible fields needed for federation resolution.
- Client schema — exposed via introspection; filtered elements are excluded.
Key benefits
Serve each audience a tailored API
One graph, multiple tailored API experiences
Serve filtered schemas to internal, partner, and public consumers from a single source graph. Each audience sees the schema view defined by its contract. Source graph changes automatically recompose dependent contracts.
Sensitive fields can be excluded from external schemas
Tag fields with @tag(name: "internal") or @tag(name: "sensitive") and exclude those tags in your public contract. The client schema excludes filtered elements from introspection, while the router schema retains what it needs for federation.
Contracts recompose automatically from source changes
When a subgraph is created, updated, moved, or deleted, or when the source graph changes, dependent contracts recompose automatically. You update the source graph once, and contracts stay synchronized from that source.
Each contract has its own router deployment
Each contract has its own router deployment, with separate analytics and persisted operations. Schema checks automatically validate contracts.
Schema checks run on contracts automatically
Schema checks automatically validate contracts, so contract schemas are checked when source changes are evaluated.
How schema contracts work
01
Annotate schema elements
Add @tag directives to supported schema elements in your source graph, including objects, interfaces, inputs, types, and fields. Tags identify which elements should be excluded from specific contract views, such as @tag(name: "internal") or @tag(name: "partner-a").
02
Create the contract
Run wgc contract create and specify which tags to exclude, for example --exclude sensitive or --exclude private. The contract inherits labels from the source graph and follows the source graph namespace.
03
Two schemas are generated
The control plane produces two schemas: a router schema used internally for query planning, including @inaccessible fields needed for federation, and a client schema exposed via introspection that excludes filtered elements.
04
Contract router deployment serves the tailored schema
Deploy a router for the contract. Consumers query that router and see the contract's client schema. Other consumers can use the source graph or another contract, depending on how the graph is deployed.
05
Contracts recompose automatically
When the source graph changes, dependent contracts recompose automatically. This includes subgraph changes, source graph namespace moves, label matcher changes, and new monograph schema publishes.
Use cases
When teams use schema contracts
Public vs. internal API
Security
Internal fields, admin flags, social security numbers, or internal user IDs can be tagged with @tag(name: "internal") or @tag(name: "sensitive"). A public contract excludes those tags so external consumers see a filtered schema through the public contract router. Internal applications can use the source graph or a separate internal contract, depending on how the graph is deployed.
Partner-specific APIs
Partners
Different partners may need different subsets of the API based on their integration agreements. Fields can be tagged with partner-specific identifiers like @tag(name: "partner-a"). Separate contracts can be created for each partner, giving each partner a customized API experience without maintaining separate graphs.
Legacy compatibility during migration
Migration
A company modernizing its API may need to serve the original schema to legacy consumers during migration. New fields can be tagged with @tag(name: "v2"). A legacy contract excludes v2 tags, while a modern contract can expose the newer schema view. Contracts recompose automatically as the source graph changes.
Multi-tenant schema visibility
Multi-tenant
A SaaS platform serves multiple tenants who should only see relevant schema portions. Tenant-specific features can be tagged, and contracts can be created per tenant to filter each tenant's visible schema. This supports schema-level visibility for tenant-specific feature sets.
When to use schema contracts
When to use
- You need to expose different schema views to different audiences — public consumers, partners, or internal teams.
- Your graph contains sensitive or internal fields that should be excluded from external schema views.
- You are managing multiple API consumers and want to avoid maintaining separate graphs for each.
When not to use
- You only have one audience and all consumers should see the same schema.
- You are not on a Pro or Enterprise plan — Schema Contracts are available on Pro and Enterprise.
- You have not yet set up a source federated graph or monograph with
@tagannotations.
Start serving tailored APIs from one source graph
Schema Contracts are available on Pro and Enterprise plans.