Creating a Custom Apollo Router Core Binary

Compile a custom router binary from source


Learn how to compile a custom binary from Apollo Router Core source, which is required to create custom native Rust plugins for the router.

⚠️ Apollo doesn't recommend creating native plugins for the Apollo Router Core or GraphOS Router, for the following reasons:

  • Native plugins require familiarity with programming in Rust.

  • Native plugins require compiling a custom router binary from source, which can introduce unexpected behavior in your router that's difficult to diagnose and support.

Instead, for most router customizations, Apollo recommends creating either a Rhai script or an external coprocessor . Both of these customizations are supported by Apollo and provide strong separation of concerns and fault isolation.

If you must create a native plugin, please open a GitHub issue , and Apollo can investigate adding the custom capability to the stock router binary.

 note
The Apollo Router Core source code and all its distributions are made available under the Elastic License v2.0 (ELv2) license .

Prerequisites

To compile the router, you need to have the following installed:

After you install the above, also install the cargo-xtask and cargo-scaffold crates:

sh
1cargo install cargo-xtask
2cargo install cargo-scaffold

1. Create a new project

  1. Use the cargo-scaffold command to create a project for your custom router:

    Bash
    1cargo-scaffold scaffold https://github.com/apollographql/router.git -r apollo-router-scaffold/templates/base -t main
  2. The cargo-scaffold command prompts you for some configuration settings. For the purposes of this tutorial, set your project's name to starstuff.

  3. After your project is created, change to the starstuff directory:

    Bash
    1cd starstuff

The generated project has the following layout:

Bash
1starstuff
2├── Cargo.toml       # Dependencies are declared here
3├── README.md
4├── router.yaml      # Router yaml config
5├── src
6   ├── main.rs      # Entry point
7   └── plugins      # Custom plugins are located here
8       └── mod.rs
9└── xtask            # Build support files
10    ├── Cargo.toml
11    └── src
12        └── main.rs

The router uses an auto-discovery mechanism for plugins, so any plugins you add via dependency are automatically available to the router at runtime.

2. Compile the router

Create a debug build of the router with the following command:

Bash
1cargo build

The resulting debug binary is located in target/debug/router.

To create a release build for production environments, use this command instead:

Bash
1cargo build --release

The resulting release binary is now located in target/release/router.

3. Run the compiled binary

Now you can test out your compiled router with an example supergraph schema.

  1. Download the example schema with the following command:

    Bash
    1curl -sSL https://supergraph.demo.starstuff.dev/ > supergraph-schema.graphql
  2. Run the router and provide the example schema like so:

    Bash
    1cargo run -- --hot-reload --config router.yaml --supergraph supergraph-schema.graphql

    During development, it's helpful to use cargo run to run the router.

If you're using managed federation, you set the APOLLO_KEY and APOLLO_GRAPH_REF environment variables instead of specifying the supergraph schema as a file. For details, see this section .

4. Create a plugin

  1. From within your project directory, scaffold a new plugin with the following command:

    Bash
    1cargo router plugin create hello_world
  2. The command prompts you to choose a starting template:

    Bash
    1Select a plugin template:
    2> "basic"
    3"auth"
    4"tracing"

    The available templates are:

    • basic - a barebones plugin

    • auth - an authentication plugin for making an external call

    • tracing - a telemetry plugin that adds a custom metric span and a log message

    For the purposes of this tutorial, choose basic.

  3. Add configuration options for the created plugin to your router.yaml file:

    YAML
    router.yaml
    1plugins:
    2  starstuff.hello_world:
    3    message: "starting my plugin"
  4. Run the router again:

    Bash
    1cargo run -- --hot-reload --config router.yaml --supergraph supergraph-schema.graphql

    This time, you should see a log line like the following:

    Bash
    12022-05-21T09:16:33.160288Z  INFO router::plugins::hello_world: starting my plugin

Nice work! You now have a custom router binary with an associated plugin. Next, you can extend the plugin with the functionality you need or add more plugins.

Removing a plugin

To remove a previously added plugin from your router project, use the following command:

Bash
1cargo router plugin remove hello_world

Note that depending on the structure of your plugin, the command might fail to remove all of its associated files.

Memory allocator

On Linux the apollo-router crate sets jemalloc as the global memory allocator for Rust to reduce memory fragmentation. Future versions may do so on more platforms, or switch to yet a different allocator. This is enabled by default and controlled by a global-allocator Cargo feature flag. If you want to choose a different allocator, disable it in your Cargo.toml:

toml
1[dependencies]
2apollo-router = {version = "[…]", default-features = false}

If you make a library crate, also specify default-features = false in order to leave the choice open for the eventual executable crate. (Cargo default features are only disabled if all dependents specify default-features = false.)

Docker

You can use the provided Dockerfile to build a release container.

Make sure your router is configured to listen to 0.0.0.0 so you can query it from outside the container:

yml
1 supergraph:
2   listen: 0.0.0.0:4000

Use your APOLLO_KEY and APOLLO_GRAPH_REF environment variables to run the router in managed federation.

Bash
1   docker build -t my_custom_router .
2   docker run -e APOLLO_KEY="your apollo key" -e APOLLO_GRAPH_REF="your apollo graph ref" my_custom_router

Otherwise add a COPY step to the Dockerfile, and edit the entrypoint:

dockerfile
1# Copy configuration for docker image
2COPY router.yaml /dist/config.yaml
3# Copy supergraph for docker image
4COPY my_supergraph.graphql /dist/supergraph.graphql
5
6# [...] and change the entrypoint
7
8# Default executable is the router
9ENTRYPOINT ["/dist/router", "-s", "/dist/supergraph.graphql"]