From graphql-federation
GraphQL Federation skill for creating correct federation subgraphs. Use when: (1) Creating new federation subgraphs, (2) Adding entities with @key directives, (3) Extending types across subgraphs, (4) Using federation directives (@shareable, @external, @override, @provides, @requires, @inaccessible, @interfaceObject, @authenticated, @requiresScopes), (5) Debugging composition errors, (6) Understanding federation rules and patterns. MANDATORY TRIGGERS: federation, subgraph, @key, entity, federated graph, supergraph, GraphQL composition, router schema
npx claudepluginhub wundergraph/graphql-federation-skill --plugin graphql-federationThis skill uses the workspace's default tool permissions.
Create correct GraphQL federation subgraphs following WunderGraph Cosmo composition rules.
Implements structured self-debugging workflow for AI agent failures: capture errors, diagnose patterns like loops or context overflow, apply contained recoveries, and generate introspection reports.
Monitors deployed URLs for regressions in HTTP status, console errors, performance metrics, content, network, and APIs after deploys, merges, or upgrades.
Provides React and Next.js patterns for component composition, compound components, state management, data fetching, performance optimization, forms, routing, and accessible UIs.
Create correct GraphQL federation subgraphs following WunderGraph Cosmo composition rules.
Subgraph: A GraphQL microservice contributing to the federated graph.
Federated Graph/Supergraph: The composed GraphQL interface for clients.
Router: Plans operations, routes requests to subgraphs, joins data.
Entity: A type with @key directive resolvable across subgraphs.
Router Schema vs Client Schema: Router sees all fields; clients don't see @inaccessible items.
# Basic entity
type User @key(fields: "id") {
id: ID!
name: String!
}
# Multiple keys
type Product @key(fields: "id") @key(fields: "sku") {
id: ID!
sku: String!
name: String!
}
# Composite key
type Review @key(fields: "author { id } product { id }") {
author: User!
product: Product!
rating: Int!
}
# Non-resolvable key (reference only, can't resolve this entity)
type User @key(fields: "id", resolvable: false) {
id: ID!
}
Key Rules:
# When same field exists in multiple subgraphs
type User @key(fields: "id") {
id: ID!
name: String! @shareable # Can be defined in other subgraphs
}
# Object-level shareable applies to all fields
type User @key(fields: "id") @shareable {
id: ID!
name: String!
email: String!
}
Shareable Rules:
# Mark fields resolved by another subgraph
extend type User @key(fields: "id") {
id: ID! @external
name: String! @external
reviews: [Review!]! # This subgraph resolves reviews
}
External Rules:
type Product @key(fields: "id") {
id: ID!
price: Float! @external
currency: String! @external
formattedPrice: String! @requires(fields: "price currency")
}
Requires Rules:
@requires(fields: "details { weight }")type Query {
topProducts: [Product!]! @provides(fields: "name description")
}
type Product @key(fields: "id") {
id: ID!
name: String! @external
description: String! @external
}
Provides Rules:
# In new subgraph, taking over from "old-service"
type User @key(fields: "id") {
id: ID!
name: String! @override(from: "old-service")
}
Override Rules:
type User @key(fields: "id") {
id: ID!
name: String!
internalId: String! @inaccessible # Hidden from clients
}
# Entire type can be inaccessible
type InternalMetrics @inaccessible {
requestCount: Int!
}
Inaccessible Rules:
# Subgraph A defines the interface
interface Media @key(fields: "id") {
id: ID!
title: String!
}
type Book implements Media @key(fields: "id") {
id: ID!
title: String!
author: String!
}
# Subgraph B adds fields to ALL implementations
type Media @key(fields: "id") @interfaceObject {
id: ID!
reviews: [Review!]! # Added to Book and all Media types
}
InterfaceObject Rules:
type Query {
publicData: String!
privateData: String! @authenticated
adminData: String! @requiresScopes(scopes: [["admin"], ["superuser"]])
}
# Type-level auth
type SecretDocument @authenticated @requiresScopes(scopes: [["read:secrets"]]) {
content: String!
}
# Subgraph A - owns User
type User @key(fields: "id") {
id: ID!
name: String!
email: String!
}
# Subgraph B - extends User with posts
extend type User @key(fields: "id") {
id: ID! @external
posts: [Post!]!
}
type Post @key(fields: "id") {
id: ID!
title: String!
author: User!
}
type Mutation {
createUser(input: CreateUserInput!): User!
}
# Entity returned from mutation allows field resolution from other subgraphs
type User @key(fields: "id") {
id: ID!
name: String!
}
interface Node @key(fields: "id") {
id: ID!
}
type User implements Node @key(fields: "id") {
id: ID!
name: String!
}
type Product implements Node @key(fields: "id") {
id: ID!
title: String!
}
# ERROR: Field defined in multiple subgraphs without @shareable
# Subgraph A
type User @key(fields: "id") {
id: ID!
name: String! # Missing @shareable
}
# Subgraph B
type User @key(fields: "id") {
id: ID!
name: String! # Conflict!
}
# FIX: Add @shareable to both
type User @key(fields: "id") {
id: ID!
name: String! @shareable
}
# ERROR: Field cannot be resolved from Query entry point
# Subgraph A
type Query {
user: User! # Only in A
}
type User {
id: ID!
name: String! # Only in A
}
# Subgraph B
type User {
email: String! # Only in B, but User has no @key!
}
# FIX: Add @key to make User an entity
type User @key(fields: "id") {
id: ID!
name: String!
}
# ERROR: @requires on non-external field
type Product @key(fields: "id") {
id: ID!
price: Float! # Missing @external
formattedPrice: String! @requires(fields: "price")
}
# FIX: Mark as external
type Product @key(fields: "id") {
id: ID!
price: Float! @external
formattedPrice: String! @requires(fields: "price")
}
For detailed directive specifications, see:
references/directives.md - Complete directive documentationreferences/composition-rules.md - Composition validation rulesreferences/patterns.md - Advanced federation patterns