Source profileQuality 92/100

agents-inc/skills/src/skills/api-graphql-mercurius/SKILL.md

api-graphql-mercurius

GraphQL server for Fastify with Mercurius — loaders, subscriptions, federation, JIT compilation

Source repository stars
23
Declared platforms
0
Static risk flags
0
Last source update
2026-08-09
Source checked
2026-08-28

Decision brief

What it does: where it fits

Quick Guide: Use Mercurius as a Fastify plugin for GraphQL APIs with built-in loader batching (solves N+1), JIT query compilation, subscriptions via WebSocket, and federation support. Register with app.register(mercurius, { schema, resolvers, loaders }). Loaders are Mercurius's…

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/agents-inc/skills --skill "src/skills/api-graphql-mercurius"
    Safe inspection promptEditorial

    Inspect the Agent Skill "api-graphql-mercurius" from https://github.com/agents-inc/skills/blob/81d43a51211aca12c85dcc16085fa99014ec548e/src/skills/api-graphql-mercurius/SKILL.md at commit 81d43a51211aca12c85dcc16085fa99014ec548e. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      CRITICAL: Before Using This Skill

      All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering, import type, named constants)

      Building GraphQL APIs on Fastify (Mercurius is Fastify-native)Need automatic batching/caching for N+1 query prevention (loader system)Want JIT query compilation for production performance
    2. 02

      Philosophy

      Fastify-native GraphQL. Mercurius is not a standalone server bolted onto Fastify — it is a Fastify plugin that deeply integrates with Fastify's lifecycle, encapsulation model, and plugin system. This means your GraphQL API inherits Fastify's performance characteristics and plugi…

      Fastify-native GraphQL. Mercurius is not a standalone server bolted onto Fastify — it is a Fastify plugin that deeply integrates with Fastify's lifecycle, encapsulation model, and plugin system. This means your GraphQL…Loaders over DataLoader. Instead of requiring a separate DataLoader library, Mercurius provides a built-in loader system. Loaders are defined per-type/per-field and receive batched queries automatically. This is simpler…JIT for production. Mercurius uses graphql-jit to compile frequently-executed queries into optimized V8 functions. After a configurable threshold of executions, subsequent runs of the same query bypass the GraphQL execu…
    3. 03

      Core Patterns

      Register Mercurius as a Fastify plugin with schema (SDL string), resolvers, and optional loaders.

      preParsing - Before query string parsing (tracing, query preprocessing)preValidation - After parsing, before validation (skipped for cached queries)preExecution - Before execution (auth, rate limiting, query modification)
    4. 04

      Pattern 1: Plugin Registration

      Register Mercurius as a Fastify plugin with schema (SDL string), resolvers, and optional loaders.

      Register Mercurius as a Fastify plugin with schema (SDL string), resolvers, and optional loaders.Why good: JIT threshold as named constant, GraphiQL disabled in production, loaders passed at registration level alongside resolversFull registration with context, error handling, and all options: examples/core.md
    5. 05

      Pattern 2: Loaders (N+1 Prevention)

      Loaders are Mercurius's primary mechanism for batch data fetching. Define them per-type per-field. Each loader receives an array of queries (batched requests) and must return an array of results in the same order.

      Loaders are Mercurius's primary mechanism for batch data fetching. Define them per-type per-field. Each loader receives an array of queries (batched requests) and must return an array of results in the same order.Why good: Single bulk query replaces N individual queries, result array matches input order (required), batching is automatic per-requestGotcha: The returned array MUST match the length and order of queries — Mercurius maps results by index, not by key.

    Permission review

    Static risk signals and limitations

    No configured static risk pattern was detected

    This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score92/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars23SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    agents-inc/skills
    Skill path
    src/skills/api-graphql-mercurius/SKILL.md
    Commit
    81d43a51211aca12c85dcc16085fa99014ec548e
    License
    MIT
    Collected
    2026-08-28
    Default branch
    main
    View the original SKILL.md

    GraphQL with Mercurius

    Quick Guide: Use Mercurius as a Fastify plugin for GraphQL APIs with built-in loader batching (solves N+1), JIT query compilation, subscriptions via WebSocket, and federation support. Register with app.register(mercurius, { schema, resolvers, loaders }). Loaders are Mercurius's killer feature: define them per-type to batch field resolution automatically. Use jit: 1 to enable query compilation for production performance.


    <critical_requirements>

    CRITICAL: Before Using This Skill

    All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering, import type, named constants)

    (You MUST define loaders for any field that fetches related data — loaders solve the N+1 problem automatically through batching)

    (You MUST use named constants for all numeric values — JIT thresholds, query depth limits, port numbers)

    (You MUST return an array from loaders matching the exact length and order of the queries parameter)

    (You MUST use fastify.graphql.pubsub.publish() inside mutations to trigger subscriptions — not external pubsub directly)

    </critical_requirements>


    Auto-detection: Mercurius, mercurius, app.graphql, fastify.graphql, mercurius loaders, mercurius subscription, pubsub.publish, pubsub.subscribe, @mercuriusjs/federation, @mercuriusjs/gateway, mercurius-codegen, MercuriusContext, graphql-jit, withFilter, preParsing, preValidation, preExecution, onResolution

    When to use:

    • Building GraphQL APIs on Fastify (Mercurius is Fastify-native)
    • Need automatic batching/caching for N+1 query prevention (loader system)
    • Want JIT query compilation for production performance
    • Building federated GraphQL services with @mercuriusjs/federation
    • Need real-time subscriptions via WebSocket with built-in pubsub
    • Want GraphQL lifecycle hooks (preParsing, preValidation, preExecution, onResolution)

    When NOT to use:

    • Not using Fastify (Mercurius is Fastify-only)
    • Need a framework-agnostic GraphQL server
    • Building a standalone schema-first design tool (use the schema library directly)
    • Simple REST endpoints without GraphQL requirements

    Key patterns covered:

    • Plugin registration with schema, resolvers, and loaders
    • Loader system for batched data fetching (the core differentiator)
    • JIT compilation configuration for production performance
    • Subscriptions with built-in pubsub and withFilter
    • Federation services and gateway composition
    • TypeScript context typing with MercuriusContext augmentation
    • GraphQL lifecycle hooks for cross-cutting concerns

    Detailed Resources:


    Philosophy

    Fastify-native GraphQL. Mercurius is not a standalone server bolted onto Fastify — it is a Fastify plugin that deeply integrates with Fastify's lifecycle, encapsulation model, and plugin system. This means your GraphQL API inherits Fastify's performance characteristics and plugin architecture naturally.

    Loaders over DataLoader. Instead of requiring a separate DataLoader library, Mercurius provides a built-in loader system. Loaders are defined per-type/per-field and receive batched queries automatically. This is simpler than manually instantiating DataLoader instances per-request and is the primary mechanism for solving the N+1 problem.

    JIT for production. Mercurius uses graphql-jit to compile frequently-executed queries into optimized V8 functions. After a configurable threshold of executions, subsequent runs of the same query bypass the GraphQL execution engine entirely — delivering significant performance gains for repeated queries.

    Federation as a plugin. Federation support is split into separate packages (@mercuriusjs/federation for services, @mercuriusjs/gateway for composition), keeping the core library lean for non-federated use cases.


    Core Patterns

    Pattern 1: Plugin Registration

    Register Mercurius as a Fastify plugin with schema (SDL string), resolvers, and optional loaders.

    import Fastify from "fastify";
    import mercurius from "mercurius";
    
    const JIT_THRESHOLD = 1;
    const SERVER_PORT = 3000;
    
    const app = Fastify({ logger: true });
    
    const schema = `
      type Query {
        user(id: ID!): User
        users: [User!]!
      }
    
      type User {
        id: ID!
        name: String!
        posts: [Post!]!
      }
    
      type Post {
        id: ID!
        title: String!
      }
    `;
    
    app.register(mercurius, {
      schema,
      resolvers,
      loaders,
      jit: JIT_THRESHOLD,
      graphiql: process.env.NODE_ENV !== "production",
    });
    

    Why good: JIT threshold as named constant, GraphiQL disabled in production, loaders passed at registration level alongside resolvers

    Full registration with context, error handling, and all options: examples/core.md


    Pattern 2: Loaders (N+1 Prevention)

    Loaders are Mercurius's primary mechanism for batch data fetching. Define them per-type per-field. Each loader receives an array of queries (batched requests) and must return an array of results in the same order.

    const loaders = {
      User: {
        async posts(
          queries: Array<{ obj: User; params: Record<string, unknown> }>,
          context: MercuriusContext,
        ) {
          const userIds = queries.map(({ obj }) => obj.id);
          const allPosts = await fetchPostsByUserIds(userIds);
          // Return array matching queries order
          return queries.map(({ obj }) =>
            allPosts.filter((post) => post.authorId === obj.id),
          );
        },
      },
    };
    

    Why good: Single bulk query replaces N individual queries, result array matches input order (required), batching is automatic per-request

    Gotcha: The returned array MUST match the length and order of queries — Mercurius maps results by index, not by key.

    Full loader patterns with caching options: examples/core.md


    Pattern 3: Resolver Structure

    Resolvers follow the standard GraphQL signature: (parent, args, context, info). The context includes the Fastify reply object for accessing Fastify decorators.

    const resolvers = {
      Query: {
        user: async (
          _parent: unknown,
          args: { id: string },
          context: MercuriusContext,
        ) => {
          return context.reply.server.db.findUser(args.id);
        },
        users: async (
          _parent: unknown,
          _args: unknown,
          context: MercuriusContext,
        ) => {
          return context.reply.server.db.listUsers();
        },
      },
    };
    

    Why good: Accesses Fastify decorators via context.reply.server, standard GraphQL resolver signature

    Complete resolver examples with mutations: examples/core.md


    Pattern 4: TypeScript Context Typing

    Augment the MercuriusContext interface to get type-safe context in resolvers and loaders.

    import type { FastifyRequest, FastifyReply } from "fastify";
    
    const buildContext = async (req: FastifyRequest, _reply: FastifyReply) => {
      return {
        userId: req.headers["x-user-id"] as string | undefined,
      };
    };
    
    type PromiseType<T> = T extends PromiseLike<infer U> ? U : T;
    
    declare module "mercurius" {
      interface MercuriusContext extends PromiseType<
        ReturnType<typeof buildContext>
      > {}
    }
    
    // Registration
    app.register(mercurius, {
      schema,
      resolvers,
      context: buildContext,
    });
    

    Why good: Context type is derived from the builder function, no manual interface duplication, resolvers get full type inference on ctx.userId

    Full TypeScript patterns with codegen: examples/core.md


    Pattern 5: Subscriptions with PubSub

    Enable subscriptions for real-time data. Mercurius provides a built-in pubsub system accessible via context.

    const NOTIFICATION_TOPIC = "NOTIFICATION_ADDED";
    
    const resolvers = {
      Mutation: {
        addNotification: async (
          _parent: unknown,
          args: { message: string },
          context: MercuriusContext,
        ) => {
          const notification = { id: generateId(), message: args.message };
          await context.pubsub.publish({
            topic: NOTIFICATION_TOPIC,
            payload: { notificationAdded: notification },
          });
          return notification;
        },
      },
      Subscription: {
        notificationAdded: {
          subscribe: async (
            _parent: unknown,
            _args: unknown,
            context: MercuriusContext,
          ) => {
            return context.pubsub.subscribe(NOTIFICATION_TOPIC);
          },
        },
      },
    };
    

    Why good: Topic as named constant, pubsub accessed from context (Mercurius-managed), subscribe returns async iterator

    Full subscription patterns with withFilter and Redis: examples/subscriptions.md


    Pattern 6: Federation Services

    Build federated services with @mercuriusjs/federation. Define __resolveReference as a loader for batch entity resolution.

    import mercuriusFederation from "@mercuriusjs/federation";
    
    const schema = `
      extend type Query {
        me: User
      }
    
      type User @key(fields: "id") {
        id: ID!
        name: String!
      }
    `;
    
    const loaders = {
      User: {
        async __resolveReference(queries: Array<{ obj: { id: string } }>) {
          const ids = queries.map(({ obj }) => obj.id);
          const users = await fetchUsersByIds(ids);
          return queries.map(({ obj }) => users.find((u) => u.id === obj.id));
        },
      },
    };
    
    app.register(mercuriusFederation, { schema, resolvers, loaders });
    

    Why good: __resolveReference as loader prevents N+1 on entity resolution (strongly recommended by Mercurius docs), batch fetches all referenced entities at once

    Full federation with gateway: examples/federation.md


    Pattern 7: GraphQL Lifecycle Hooks

    Mercurius provides hooks for cross-cutting concerns at specific points in the GraphQL execution lifecycle.

    Hook execution order:

    1. preParsing - Before query string parsing (tracing, query preprocessing)
    2. preValidation - After parsing, before validation (skipped for cached queries)
    3. preExecution - Before execution (auth, rate limiting, query modification)
    4. onResolution - After execution completes (metrics, response logging)
    app.graphql.addHook("preExecution", async (schema, document, context) => {
      const startTime = performance.now();
      context.startTime = startTime;
    });
    
    app.graphql.addHook("onResolution", async (execution, context) => {
      const duration = performance.now() - context.startTime;
      context.reply.server.log.info({ duration }, "GraphQL query executed");
    });
    

    Why good: Hooks integrate with Fastify's logging, run at precise lifecycle points, can modify schema/document/variables in preExecution

    Warning: Modifying schema or document in preExecution disables JIT compilation for that query.

    Full hook patterns: reference.md


    Pattern 8: JIT Compilation Configuration

    Enable JIT to compile frequently-executed queries into optimized V8 functions.

    const JIT_THRESHOLD = 1;
    const MAX_QUERY_DEPTH = 10;
    
    app.register(mercurius, {
      schema,
      resolvers,
      jit: JIT_THRESHOLD,
      queryDepth: MAX_QUERY_DEPTH,
    });
    

    Why good: jit: 1 compiles after first execution (suitable for production with repeated queries), queryDepth prevents abuse, both values as named constants

    Gotcha: JIT is disabled (default 0) out of the box. Set jit: 1 for production. Setting it higher (e.g., 5) delays compilation until the query has been seen N times, which helps avoid compiling one-off queries.


    <red_flags>

    RED FLAGS

    High Priority Issues

    • No loaders defined for related data fields — Every field that fetches associated data (e.g., User.posts, Post.author) should use a loader, not inline resolver queries. Without loaders, you get the classic N+1 problem.
    • Loader returns wrong length/order — The returned array MUST match the queries array by index. Returning fewer/more items or in wrong order corrupts the response silently.
    • __resolveReference as resolver instead of loader in federation — Causes N+1 on entity resolution across services. The docs strongly recommend defining it as a loader.
    • JIT left at default (disabled)jit: 0 means no JIT compilation. Set jit: 1 for production workloads with repeated queries.

    Medium Priority Issues

    • Not using context function for per-request data — Accessing request headers or auth tokens requires a context builder function, not Fastify decorators alone
    • GraphiQL enabled in production — Set graphiql: false or conditionally disable based on NODE_ENV
    • Missing queryDepth limit — Without depth limiting, deeply nested queries can exhaust server resources
    • Modifying schema/document in preExecution — Disables JIT compilation for that query execution

    Common Mistakes

    • Using external DataLoader instead of Mercurius loaders — Mercurius loaders are built-in and request-scoped by default; no need for manual DataLoader instantiation
    • Forgetting subscription: true in registration — Subscriptions are disabled by default; subscription resolvers silently fail without this option
    • Publishing with wrong payload shape — The payload in pubsub.publish() must match the subscription field name exactly (e.g., { notificationAdded: data } for a notificationAdded subscription)
    • Calling addHook before app.ready() — GraphQL hooks must be registered after app.ready() or inside a Fastify plugin that ensures readiness

    Detailed anti-pattern code examples: reference.md

    Gotchas & Edge Cases

    • Loader caching is enabled by default — Within a single request, identical loader calls return cached results. Disable with opts: { cache: false } when data changes mid-request
    • preValidation is skipped for cached queries — If a query is parsed from cache, validation hooks do not fire
    • Subscription context is different from query context — Subscription context receives the WebSocket connection info, not the HTTP request. Use subscription.context option for custom subscription context
    • connection_init payload goes into request.headers — During WebSocket handshake, properties from the client's connection_init payload are copied into request headers automatically
    • Gateway mode disables local schema/resolvers/loaders — When running as a gateway, you cannot define schema, resolvers, or loaders on the gateway instance
    • queryDepth must be at least 7 for GraphiQL — GraphiQL's introspection query requires depth 7+; lower values break the IDE

    </red_flags>


    <critical_reminders>

    CRITICAL REMINDERS

    All code must follow project conventions in CLAUDE.md

    (You MUST define loaders for any field that fetches related data — loaders solve the N+1 problem automatically through batching)

    (You MUST use named constants for all numeric values — JIT thresholds, query depth limits, port numbers)

    (You MUST return an array from loaders matching the exact length and order of the queries parameter)

    (You MUST use fastify.graphql.pubsub.publish() inside mutations to trigger subscriptions — not external pubsub directly)

    Failure to follow these rules will cause N+1 performance problems, corrupted GraphQL responses, and broken subscriptions.

    </critical_reminders>

    Frequently asked questions

    What to verify before installation and use

    What does the api-graphql-mercurius source document cover?

    Quick Guide: Use Mercurius as a Fastify plugin for GraphQL APIs with built-in loader batching (solves N+1), JIT query compilation, subscriptions via WebSocket, and federation support. Register with app.register(mercurius, { schema, resolvers, loaders }). Loaders are Mercurius's…

    How do I install api-graphql-mercurius?

    The source record exposes this install command: npx skills add https://github.com/agents-inc/skills --skill "src/skills/api-graphql-mercurius". Inspect the command and pinned source before running it.

    Alternatives

    Compare before choosing

    Computed 10045,960

    coreyhaines31/marketingskills

    ab-testing

    When the user wants to plan, design, or implement an A/B test or experiment, or build a growth experimentation program. Also use when the user mentions "A/B test," "split test," "experiment," "test this change," "variant copy," "multivariate test," "hypothesis," "should I test this," "which version is better," "test two versions," "statistical significance," "how long should I run this test," "growth experiments," "experiment velocity," "experiment backlog," "ICE score," "experimentation program

    Computed 10029,236

    garrytan/gbrain

    bulk-ingestion

    End-to-end discipline for turning any large data source (audio libraries, email takeouts, document corpora, chat exports, API dumps) into brain pages at scale. The lifecycle spine: SCHEMA → ACCESS → TRIAL → EVALUATE → IMPROVE → CODIFY → TEST → SKILLIFY → BULK → MONITOR. State is tracked in a durable JSON manifest (see MANIFEST-PATTERN.md) so any crash, session boundary, or subagent fan-out resumes from ground truth instead of memory.

    Computed 10025,136

    alirezarezvani/claude-skills

    app-store-optimization

    App Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklist

    Computed 1005,277

    dotnet/skills

    migrate-vstest-to-mtp

    Migrates .NET test projects from VSTest to Microsoft.Testing.Platform (MTP). Use when user asks to "migrate to MTP", "switch from VSTest", "enable Microsoft.Testing.Platform", "use MTP runner", set OutputType=Exe only for test projects in Directory.Build.props, or mentions EnableMSTestRunner, EnableNUnitRunner, or UseMicrosoftTestingPlatformRunner. USE FOR: MTP behavioral differences vs VSTest (exit code 8, zero tests discovered, --ignore-exit-code, TESTINGPLATFORM_EXITCODE_IGNORE); centralizing