git clone https://github.com/Intense-Visions/harness-engineering
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/codex/graphql-federation-pattern" ~/.claude/skills/intense-visions-harness-engineering-graphql-federation-pattern-8ec2ab && rm -rf "$T"
agents/skills/codex/graphql-federation-pattern/SKILL.mdGraphQL Federation Pattern
Compose a unified GraphQL API from independently deployed subgraph services using Apollo Federation
When to Use
- Multiple teams own different domains and need independent deployment
- A monolithic GraphQL schema has grown too large for one service
- You need to extend types across service boundaries (e.g., adding
toorders
from the orders service)User - Migrating from schema stitching to a standards-based composition model
Instructions
- Each subgraph owns its domain types. The users service defines
, the orders service definesUser
. No type is defined in two places — types are extended across boundaries.Order
# users subgraph type User @key(fields: "id") { id: ID! name: String! email: String! } type Query { user(id: ID!): User }
-
Use
to mark entity types. An entity is a type that can be referenced and extended by other subgraphs. The@key
directive specifies which fields uniquely identify the entity.@key -
Extend entities in other subgraphs with stub types. The orders service references
without redefining it — it provides only the key field and adds new fields.User
# orders subgraph type User @key(fields: "id") { id: ID! orders: [Order!]! } type Order @key(fields: "id") { id: ID! total: Money! status: OrderStatus! customer: User! }
- Implement
for each entity. This resolver is called by the gateway when it needs to hydrate a stub entity. It receives the key fields and returns the full object.__resolveReference
const resolvers = { User: { __resolveReference: (ref: { id: string }, { dataSources }) => { return dataSources.users.findById(ref.id); }, }, };
- Use the Apollo Router (or Gateway) to compose subgraphs. The router fetches schemas from each subgraph, composes them into a supergraph, and routes incoming queries to the appropriate subgraphs.
# supergraph-config.yaml subgraphs: users: routing_url: http://users-service:4001/graphql schema: subgraph_url: http://users-service:4001/graphql orders: routing_url: http://orders-service:4002/graphql schema: subgraph_url: http://orders-service:4002/graphql
-
Use
for fields that multiple subgraphs can resolve. In Federation v2, fields are exclusive by default. Mark fields@shareable
when multiple subgraphs need to return the same field.@shareable -
Use
to migrate fields between subgraphs. When moving a field from one subgraph to another, the new owner uses@override
to claim resolution without a breaking change.@override(from: "old-subgraph") -
Use
,@external
, and@provides
for computed fields.@requires
tells the gateway to fetch specified fields from the owning subgraph before calling the current resolver.@requires
# shipping subgraph type Order @key(fields: "id") { id: ID! weight: Float @external shippingCost: Float @requires(fields: "weight") }
-
Run composition checks in CI. Use
to validate that schema changes in one subgraph do not break the composed supergraph before deploying.rover subgraph check -
Keep the gateway stateless. The router/gateway should not contain business logic — it composes and routes. All business logic lives in subgraphs.
Details
Federation v1 vs. v2: Federation v2 (current) uses
@link to import federation directives, supports @shareable, @override, @inaccessible, and progressive @override for safe migrations. Prefer v2 for new projects.
Query planning: The gateway decomposes incoming queries into subgraph fetches. A query for
user { name orders { total } } fetches name from the users subgraph, then fetches orders from the orders subgraph using the user's id as the reference key. This happens transparently.
Performance considerations:
- Entity references add network hops — the gateway calls
on the owning subgraph__resolveReference - Use
to return extra fields alongside entities to reduce follow-up fetches@provides - Batch entity lookups in
using DataLoader__resolveReference
Ownership rules:
- A type's
fields must be resolvable by the defining subgraph@key - Only one subgraph should define a field (unless
)@shareable - Value types (types without
) must be identical across subgraphs@key
Common mistakes:
- Circular entity references that cause infinite gateway loops
- Missing
— the gateway cannot hydrate the entity__resolveReference - Changing
fields without updating all referencing subgraphs@key - Putting too many types in one subgraph, recreating the monolith
Source
https://www.apollographql.com/docs/federation/
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.