Walks you through scaffolding a native Rust plugin, wiring service hooks (router, supergraph, execution, subgraph), and testing it against your schema—without memorizing Apollo's docs.
Best for: Engineers extending Apollo Router with custom middleware or request lifecycle logic.
Creator's repository · apollographql/skills
License: MIT
---
name: apollo-router-plugin-creator
description: >
Guide for writing Apollo Router native Rust plugins. Use this skill when:
(1) users want to create a new router plugin,
(2) users want to add service hooks (router_service, supergraph_service, execution_service, subgraph_service),
(3) users want to modify an existing router plugin,
(4) users need to understand router plugin patterns or the request lifecycle.
(5) triggers on requests like "create a new plugin", "add a router plugin", "modify the X plugin", or "add subgraph_service hook".
license: MIT
allowed-tools: Read Write Edit Glob Grep
metadata:
author: apollographql
version: "1.0.0"
compatibility: "Requires Apollo Router with native plugin support"
---
# Apollo Router Plugin Creator
Create native Rust plugins for Apollo Router.
## Request Lifecycle
```
┌────────┐ ┌────────────────┐ ┌────────────────────┐ ┌───────────────────┐ ┌─────────────────────┐
│ Client │ │ Router Service │ │ Supergraph Service │ │ Execution Service │ │ Subgraph Service(s) │
└────┬───┘ └────────┬───────┘ └──────────┬─────────┘ └─────────┬─────────┘ └──────────┬──────────┘
│ │ │ │ │
│ Sends request │ │ │ │
│──────────────────────────▶ │ │ │
│ │ │ │ │
│ │ Converts raw HTTP request to GraphQL/JSON request │ │ │
│ │──────────────────────────────────────────────────────▶ │ │
│ │ │ │ │
│ │ │ Initiates query plan execution │ │
│ │ │───────────────────────────────────▶ │
│ │ │ │ │
│ │ │ ┌par [Initiates sub-operation]───────┐
│ │ │ │ │ │ │
│ │ │ │ │ Initiates sub-operation │ │
│ │ │ │ │────────────────────────────▶ │
│ │ │ │ │ │ │
│ │ │ ├[Initiates sub-operation]╌╌╌╌╌╌╌╌╌╌╌┤
│ │ │ │ │ │ │
│ │ │ │ │ Initiates sub-operation │ │
│ │ │ │ │────────────────────────────▶ │
│ │ │ │ │ │ │
│ │ │ ├[Initiates sub-operation]╌╌╌╌╌╌╌╌╌╌╌┤
│ │ │ │ │ │ │
│ │ │ │ │ Initiates sub-operation │ │
│ │ │ │ │────────────────────────────▶ │
│ │ │ │ │ │ │
│ │ │ └────────────────────────────────────┘
│ │ │ │ │
│ │ │ Assembles and returns response │ │
│ │ ◀╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌│ │
│ │ │ │ │
│ │ Returns GraphQL/JSON response │ │ │
│ ◀╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌│ │ │
│ │ │ │ │
│ Returns HTTP response │ │ │ │
◀╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌│ │ │ │
│ │ │ │ │
┌────┴───┐ ┌────────┴───────┐ ┌──────────┴─────────┐ ┌─────────┴─────────┐ ┌──────────┴──────────┐
│ Client │ │ Router Service │ │ Supergraph Service │ │ Execution Service │ │ Subgraph Service(s) │
└────────┘ └────────────────┘ └────────────────────┘ └───────────────────┘ └─────────────────────┘
```
## Service Hooks
### Service Overview
| Service | Description |
|----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `router_service` | Runs at the very beginning and very end of the HTTP request lifecycle.For example, JWT authentication is performed within the RouterService.Define router_service if your customization needs to interact with HTTP context and headers. It doesn't support access to the body property |
| `supergraph_service` | Runs at the very beginning and very end of the GraphQL request lifecycle.Define supergraph_service if your customization needs to interact with the GraphQL request or the GraphQL response. For example, you can add a check for anonymous queries. |
| `execution_service` | Handles initiating the execution of a query plan after it's been generated.Define execution_service if your customization includes logic to govern execution (for example, if you want to block a particular query based on a policy decision). |
| `subgraph_service` | Handles communication between the router and your subgraphs.Define subgraph_service to configure this communication (for example, to dynamically add HTTP headers to pass to a subgraph).Whereas other services are called once per client request, this service is called once per subgraph request that's required to resolve the client's request. Each call is passed a subgraph parameter that indicates the name of the corresponding subgraph. |
**Signatures:**
```rust
fn router_service(&self, service: router::BoxService) -> router::BoxService
fn supergraph_service(&self, service: supergraph::BoxService) -> supergraph::BoxService
fn execution_service(&self, service: execution::BoxService) -> execution::BoxService
fn subgraph_service(&self, name: &str, service: subgraph::BoxService) -> subgraph::BoxService
```
### Individual Hooks (Tower Layers)
Use `ServiceBuilder` to compose these hooks within any service:
| Hook | Purpose | Sync/Async |
|---------------------------|----------------------------------------------|------------|
| `map_request(fn)` | Transform request before proceeding | Sync |
| `map_response(fn)` | Transform response before returning | Sync |
| `checkpoint(fn)` | Validate/filter, can short-circuit | Sync |
| `checkpoint_async(fn)` | Async validation, can short-circuit | Async |
| `buffered()` | Enable service cloning (needed for async) | - |
| `instrument(span)` | Add tracing span around service | - |
| `rate_limit(num, period)` | Control request throughput | - |
| `timeout(duration)` | Set operation time limit | - |
### Choosing a Service Hook
**By data needed:**
- HTTP headers only → `router_service`
- GraphQL query/variables → `supergraph_service`
- Query plan → `execution_service`
- Per-subgraph control → `subgraph_service`
**By timing:**
- Before GraphQL parsing → `router_service` request
- After parsing, before planning → `supergraph_service` request
- After planning, before execution → `execution_service` request
- Before/after each subgraph call → `subgraph_service`
- Final response to client → `router_service` response
See [references/service-hooks.md](references/service-hooks.md) for implementation patterns.
## Quick Start
### Step 1: Create Plugin File
Create a new file `src/plugins/my_plugin.rs` with required imports:
```rust
use std::ops::ControlFlow;
use apollo_router::plugin::{Plugin, PluginInit};
use apollo_router::register_plugin;
use apollo_router::services::{router, subgraph, supergraph};
use schemars::JsonSchema;
use serde::Deserialize;
use tower::{BoxError, ServiceBuilder, ServiceExt};
const PLUGIN_NAME: &str = "my_plugin";
```
### Step 2: Define Configuration Struct
Every plugin needs a configuration struct with `Deserialize` and `JsonSchema` derives. The `JsonSchema` enables configuration validation in editors:
```rust
#[derive(Debug, Clone, Default, Deserialize, JsonSchema)]
struct MyPluginConfig {
/// Enable the plugin
enabled: bool,
// Add other configuration fields as needed
}
```
### Step 3: Define Plugin Struct
```rust
#[derive(Debug)]
struct MyPlugin {
configuration: MyPluginConfig,
}
```
### Step 4: Implement Plugin Trait
Implement the `Plugin` trait with the required `Config` type and `new` constructor:
```rust
#[async_trait::async_trait]
impl Plugin for MyPlugin {
type Config = MyPluginConfig;
async fn new(init: PluginInit<Self::Config>) -> Result<Self, BoxError> {
Ok(MyPlugin { configuration: init.config })
}
// Add service hooks based on your needs (see "Choosing a Service Hook" section)
}
```
### Step 5: Add Service Hooks
Choose which service(s) to hook based on your requirements, see [Service Overview](#service-overview) for details.
Example service hook:
```rust
fn supergraph_service(&self, service: supergraph::BoxService) -> supergraph::BoxService {
if !self.configuration.enabled {
return service;
}
ServiceBuilder::new()
.map_request(|req| { /* transform request */ req })
.map_response(|res| { /* transform response */ res })
.service(service)
.boxed()
}
```
### Step 6: Register Plugin
At the bottom of your plugin file, register it with the router:
```rust
register_plugin!("acme", "my_plugin", MyPlugin);
```
### Step 7: Add Module to mod.rs
In `src/plugins/mod.rs`, add your module:
```rust
pub mod my_plugin;
```
### Step 8: Configure in YAML
Enable your plugin in the router configuration:
```yaml
plugins:
acme.my_plugin:
enabled: true
```
## Common Patterns
For implementation patterns and code examples, see [references/service-hooks.md](references/service-hooks.md):
- Enable/disable pattern
- Request/response transformation (`map_request`, `map_response`)
- Checkpoint (early return/short-circuit)
- Context passing between hooks
- Async operations (`checkpoint_async`, `buffered`)
- Error response builders
## Examples
### Apollo Router Examples
Located in the [Apollo Router plugins directory](https://github.com/apollographql/router/tree/dev/apollo-router/src/plugins):
| Plugin | Service Hook | Pattern | Description |
|------------------------|------------------------|-------------------|-----------------------------|
| `forbid_mutations.rs` | `execution_service` | checkpoint | Simple gate on query plan |
| `expose_query_plan.rs` | execution + supergraph | Context passing | Multi-service coordination |
| `cors.rs` | `router_service` | HTTP layer | CORS handling at HTTP level |
| `headers/` | `subgraph_service` | Layer composition | Complex header manipulation |
For full code examples and testing patterns, see [references/examples.md](references/examples.md).
## Prerequisites
It is advised to have the [rust-best-practices](https://skills.sh/apollographql/skills/rust-best-practices) skill installed for writing idiomatic Rust code when developing router plugins. If installed, follow those best practices when generating or modifying plugin code.
## Resources
- [references/service-hooks.md](references/service-hooks.md) - Detailed service hook implementations
- [references/existing-plugins.md](references/existing-plugins.md) - Index of existing plugins
- [references/examples.md](references/examples.md) - Full code examples and testing patterns
- Apollo Router plugins: https://github.com/apollographql/router/tree/dev/apollo-router/src/plugins