All skills
apollographql avatar

/apollo-federation

@1e3bb5f official
by Apollo GraphQLapollographql/skills115 stars
13

Guide for authoring Apollo Federation subgraph schemas. Use this skill when: (1) creating new subgraph schemas for a federated supergraph, (2) defining or modifying entities with @key, (3) sharing types/fields across subgraphs with @shareable, (4) working with federation directives (@external, @requires, @provides, @override, @inaccessible), (5) troubleshooting composition errors, (6) any task involving federation schema design patterns.

Use this Skill: https://skilld.dev/gh/apollographql/skills/apollo-federation

This session only. Nothing lands on disk.

referencesschema-patterns.md

≈1.8k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Schema Patterns

Real-world multi-subgraph patterns and recipes for Apollo Federation.

Entity Definition and Cross-Subgraph Contributions

Multiple subgraphs contribute different fields to the same entity:

# Products subgraph
type Product @key(fields: "id") {
  id: ID!
  name: String!
  price: Int
}

# Reviews subgraph
type Product @key(fields: "id") {
  id: ID!
  reviews: [Review!]!
  averageRating: Float
}

# Inventory subgraph
type Product @key(fields: "id") {
  id: ID!
  inStock: Boolean!
}

Each subgraph defines the @key and only the fields it owns. The router composes them into a single Product type.

Value Types with @shareable

Share identical types across subgraphs when multiple subgraphs need to resolve the same fields:

# Subgraph A
type Position @shareable {
  x: Int!
  y: Int!
}

# Subgraph B
type Position @shareable {
  x: Int!
  y: Int!
}

All subgraphs must return identical values for shared fields. Use type-level @shareable for value types and field-level for selective sharing:

type Product @key(fields: "id") {
  id: ID!
  name: String! @shareable
  price: Int
}

Differing Return Types

Nullable can coerce to non-nullable:

# Subgraph A
type Position @shareable {
  x: Int!  # non-nullable
}

# Subgraph B
type Position @shareable {
  x: Int   # nullable - OK, supergraph uses nullable
}

Differing Arguments

Required in one subgraph can be optional in others. Optional arguments omitted from any subgraph are omitted from the supergraph:

# Subgraph A
type Building @shareable {
  height(units: String!): Int!  # required
}

# Subgraph B
type Building @shareable {
  height(units: String): Int!   # optional - OK
}

Entity Stubs with resolvable: false

Reference entities from another subgraph without resolving them:

# Reviews subgraph
type Review @key(fields: "id") {
  id: ID!
  body: String!
  product: Product!
}

type Product @key(fields: "id", resolvable: false) {
  id: ID!
}

No reference resolver needed. The router handles resolution via the subgraph that owns Product.

Entity Interfaces with @interfaceObject

Add fields to all implementations of an entity interface from a separate subgraph (Federation 2.3+):

# Content subgraph - defines entity interface and implementations
interface Media @key(fields: "id") {
  id: ID!
  title: String!
}

type Book implements Media @key(fields: "id") {
  id: ID!
  title: String!
  author: String!
}

# Reviews subgraph - adds fields without knowing implementations
type Media @key(fields: "id") @interfaceObject {
  id: ID!
  reviews: [Review!]!
}

Composition adds reviews to the Media interface and all its implementations.

Computed Fields with @requires

Define fields that depend on values from other subgraphs:

# Products subgraph
type Product @key(fields: "id") {
  id: ID!
  size: Int
  weight: Int
}

# Shipping subgraph
type Product @key(fields: "id") {
  id: ID!
  size: Int @external
  weight: Int @external
  shippingEstimate: String @requires(fields: "size weight")
}

The router fetches size and weight from Products first, then calls Shipping with those values.

Nested requires

shippingEstimate: String @requires(fields: "dimensions { size weight }")

Requires with arguments (Federation 2.1.2+)

weight(units: String): Int @external
shippingEstimate: String @requires(fields: "weight(units:\"KILOGRAMS\")")

Conditional Resolution with @provides

Resolve a field from another subgraph only at specific query paths:

# Products subgraph
type Product @key(fields: "id") {
  id: ID!
  name: String!
}

# Inventory subgraph
type Product @key(fields: "id") {
  id: ID!
  name: String! @external
}

type Query {
  outOfStockProducts: [Product!]! @provides(fields: "name")
  discontinuedProducts: [Product!]!  # cannot resolve name here
}

The Inventory subgraph can resolve name only when queried through outOfStockProducts.

Field Migration with @override

Move a field from one subgraph to another:

# Step 1: Add field with @override in new subgraph
# Billing subgraph
type Bill @key(fields: "id") {
  id: ID!
  amount: Int! @override(from: "Payments")
}

The router immediately starts resolving amount from Billing.

# Step 2: Remove field from Payments subgraph
type Bill @key(fields: "id") {
  id: ID!
  payment: Payment
}

# Step 3: Remove @override from Billing subgraph
type Bill @key(fields: "id") {
  id: ID!
  amount: Int!
}

Migrating Entire Entities

Apply @override to all non-key fields:

type Bill @key(fields: "id") {
  id: ID!
  amount: Int! @override(from: "Payments")
  dueDate: Date! @override(from: "Payments")
  status: BillStatus! @override(from: "Payments")
}

Progressive Migration

Gradually migrate traffic using percentages (Enterprise):

# Start with 1%
type Bill @key(fields: "id") {
  id: ID!
  amount: Int! @override(from: "Payments", label: "percent(1)")
}

# Increase to 50%
amount: Int! @override(from: "Payments", label: "percent(50)")

# Complete at 100%, then remove from original and drop @override

Best Practices

  • Don't leave progressive @override indefinitely — each label creates additional query plans
  • Share labels across fields migrating together:
type Bill @key(fields: "id") {
  id: ID!
  amount: Int! @override(from: "Payments", label: "percent(10)")
  dueDate: Date! @override(from: "Payments", label: "percent(10)")
}
  • Use a small set of known percentages (percent(5), percent(25), percent(50))
  • Use coprocessors or Rhai scripts to dynamically control override labels via feature flags

Adding Shared Fields Safely with @inaccessible

Add a field to one subgraph without breaking composition when others haven't added it yet:

# Step 1: Add field with @inaccessible
# Subgraph A
type Position @shareable {
  x: Int!
  y: Int!
  z: Int! @inaccessible  # hidden from API schema
}

# Subgraph B (not updated yet)
type Position @shareable {
  x: Int!
  y: Int!
}
# Step 2: Add field to Subgraph B
type Position @shareable {
  x: Int!
  y: Int!
  z: Int!
}

# Step 3: Remove @inaccessible from Subgraph A
type Position @shareable {
  x: Int!
  y: Int!
  z: Int!  # now visible
}

Type Merging: Unions, Interfaces, Input Types

Unions

Definitions can differ across subgraphs — the supergraph merges all members:

# Subgraph A
union Media = Book | Movie

# Subgraph B
union Media = Book | Podcast

# Supergraph
union Media = Book | Movie | Podcast

Interfaces

Adding interface fields requires updating all implementations across all subgraphs. Use entity interfaces (@key on interface + @interfaceObject) to avoid this.

Input Types

Merged using intersection — only mutual fields are preserved:

# Subgraph A
input UserInput {
  name: String!
  age: Int
}

# Subgraph B
input UserInput {
  name: String!
  email: String
}

# Supergraph - only common field
input UserInput {
  name: String!
}

Source: SKILL.md on GitHub

1 warning16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    This skill is a specialized guide for Apollo Federation schema authoring, enabling the agent to create and validate subgraph schemas using the official Apollo rover CLI. All tools, URLs, and package references are verified as authoritative vendor resources. The skill contains no malicious patterns and follows safe practices for schema management.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer7mo

    4/4 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 1e3bb5f. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 2 months ago
What it can do
Runs commands
metadata
{
  "author": "apollographql",
  "version": "1.0.2"
}
All 1 allowed tools
Bash(rover:*) Read Write Edit Glob Grep
Other metadata
compatibility
Works with any Federation 2.x compatible subgraph library (Apollo Server, GraphQL Yoga, etc.)
  • TypeScript
  • apollo
  • graphql
  • federation
  • schema
  • subgraph
  • directives
  • composition

README badge

README badge for apollographql/skills/apollo-federation

Provides guidance for authoring Apollo Federation subgraph schemas using Federation 2.x directives like @key, @shareable, @external, @requires, and @provides. Use this when defining entities, composing multiple subgraphs into a unified supergraph, or troubleshooting federation composition errors.

Generated from the current SKILL.md.

Does this skill work with Apollo Server and other GraphQL frameworks?
Yes. The skill works with any Federation 2.x compatible subgraph library, including Apollo Server, GraphQL Yoga, and others.
What Federation version does this skill target?
This skill is for Federation 2.x only. It uses the @link directive syntax and Federation 2 directives.
Can I use this skill to debug composition errors?
Yes. The skill includes guidance on troubleshooting composition errors and references composition rules and error codes.
Does this skill cover cross-subgraph type sharing?
Yes. The skill covers sharing types and fields across subgraphs using @shareable, as well as entity contributions across multiple subgraphs.
What tools does this skill rely on?
The skill uses rover (rover supergraph compose and rover subgraph check) for schema validation and composition.

Generated from the current SKILL.md. These answers refresh after source changes.