Apollo Router Quickstart
Run the router locally
Hello! Let's run Apollo Router for the first time, using the simple scenario of developing locally.
In this guide, you will:
Download and run the router as a binary.
Create a supergraph schema.
Create a router YAML configuration file.
Run the router in development mode.
Make a query to the running router.
1. Download the router
Let's start by downloading and running the router locally.
Download the latest version of the router binary with a single command line:
Bashcurl -sSL https://router.apollo.dev/download/nix/latest | sh
Download a specific router versionTo download and install a specific version of router, set the version in the download URL path.For example, to download router v2.0.0:Bashcurl -sSL https://router.apollo.dev/download/nix/v2.0.0 | sh
Optionally, go to router releases in GitHub to download and extract a bundle.
Check that your router downloaded successfully by running the
router
binary from your project's root directory:Bash./router --version
2. Create a supergraph schema
A router needs a schema for the federated graph, or supergraph, that it's orchestrating. This guide uses an example supergraph schema, which you download and provide to the router.
The example supergraph schema is composed of four subgraphs: accounts
, inventory
, products
, and reviews
. It outlines the types (Query
, Mutation
, Product
, Review
, User
) and their fields, and it specifies which subgraph is responsible for resolving each piece of data using Apollo Federation directives (@join__*
, @link
).
From your project's root directory, run the following to download and save an example supergraph schema:
curl -sSL https://supergraph.demo.starstuff.dev/ > supergraph.graphql
Example supergraph schema contents
1schema
2 @link(url: "https://specs.apollo.dev/link/v1.0")
3 @link(url: "https://specs.apollo.dev/join/v0.3", for: EXECUTION) {
4 query: Query
5 mutation: Mutation
6}
7
8directive @join__enumValue(graph: join__Graph!) repeatable on ENUM_VALUE
9
10directive @join__field(
11 graph: join__Graph
12 requires: join__FieldSet
13 provides: join__FieldSet
14 type: String
15 external: Boolean
16 override: String
17 usedOverridden: Boolean
18) repeatable on FIELD_DEFINITION | INPUT_FIELD_DEFINITION
19
20directive @join__graph(name: String!, url: String!) on ENUM_VALUE
21
22directive @join__implements(
23 graph: join__Graph!
24 interface: String!
25) repeatable on OBJECT | INTERFACE
26
27directive @join__type(
28 graph: join__Graph!
29 key: join__FieldSet
30 extension: Boolean! = false
31 resolvable: Boolean! = true
32 isInterfaceObject: Boolean! = false
33) repeatable on OBJECT | INTERFACE | UNION | ENUM | INPUT_OBJECT | SCALAR
34
35directive @join__unionMember(
36 graph: join__Graph!
37 member: String!
38) repeatable on UNION
39
40directive @link(
41 url: String
42 as: String
43 for: link__Purpose
44 import: [link__Import]
45) repeatable on SCHEMA
46
47scalar join__FieldSet
48
49enum join__Graph {
50 ACCOUNTS
51 @join__graph(name: "accounts", url: "https://accounts.demo.starstuff.dev/")
52 INVENTORY
53 @join__graph(
54 name: "inventory"
55 url: "https://inventory.demo.starstuff.dev/"
56 )
57 PRODUCTS
58 @join__graph(name: "products", url: "https://products.demo.starstuff.dev/")
59 REVIEWS
60 @join__graph(name: "reviews", url: "https://reviews.demo.starstuff.dev/")
61}
62
63scalar link__Import
64
65enum link__Purpose {
66 """
67 `SECURITY` features provide metadata necessary to securely resolve fields.
68 """
69 SECURITY
70
71 """
72 `EXECUTION` features provide metadata necessary for operation execution.
73 """
74 EXECUTION
75}
76
77type Mutation @join__type(graph: PRODUCTS) @join__type(graph: REVIEWS) {
78 createProduct(upc: ID!, name: String): Product @join__field(graph: PRODUCTS)
79 createReview(upc: ID!, id: ID!, body: String): Review
80 @join__field(graph: REVIEWS)
81}
82
83type Product
84 @join__type(graph: ACCOUNTS, key: "upc", extension: true)
85 @join__type(graph: INVENTORY, key: "upc")
86 @join__type(graph: PRODUCTS, key: "upc")
87 @join__type(graph: REVIEWS, key: "upc") {
88 upc: String!
89 weight: Int
90 @join__field(graph: INVENTORY, external: true)
91 @join__field(graph: PRODUCTS)
92 price: Int
93 @join__field(graph: INVENTORY, external: true)
94 @join__field(graph: PRODUCTS)
95 inStock: Boolean @join__field(graph: INVENTORY)
96 shippingEstimate: Int @join__field(graph: INVENTORY, requires: "price weight")
97 name: String @join__field(graph: PRODUCTS)
98 reviews: [Review] @join__field(graph: REVIEWS)
99 reviewsForAuthor(authorID: ID!): [Review] @join__field(graph: REVIEWS)
100}
101
102type Query
103 @join__type(graph: ACCOUNTS)
104 @join__type(graph: INVENTORY)
105 @join__type(graph: PRODUCTS)
106 @join__type(graph: REVIEWS) {
107 me: User @join__field(graph: ACCOUNTS)
108 recommendedProducts: [Product] @join__field(graph: ACCOUNTS)
109 topProducts(first: Int = 5): [Product] @join__field(graph: PRODUCTS)
110}
111
112type Review @join__type(graph: REVIEWS, key: "id") {
113 id: ID!
114 body: String
115 author: User @join__field(graph: REVIEWS, provides: "username")
116 product: Product
117}
118
119type User
120 @join__type(graph: ACCOUNTS, key: "id")
121 @join__type(graph: REVIEWS, key: "id") {
122 id: ID!
123 name: String @join__field(graph: ACCOUNTS)
124 username: String
125 @join__field(graph: ACCOUNTS)
126 @join__field(graph: REVIEWS, external: true)
127 reviews: [Review] @join__field(graph: REVIEWS)
128}
3. Create a router config
The router's many features are configurable via a YAML configuration file. You set your options declaratively in YAML, then point your router to it at startup.
Let's customize a common setting: the router's supergraph listen address. It's the network address and port on which the router receives client requests. By default the address is 127.0.0.1:4000
. As an exercise, let's change the port to 5555
.
In your same working directory, create a file named
router.yaml
. Open it for editing.Add the following configuration that sets
supergraph.listen
to127.0.0.1:5555
:
1supergraph:
2 listen: 127.0.0.1:5555
4. Run the router
Let's run the router in dev mode, using both the supergraph schema and YAML configuration files you created:
Run the router with these command-line options:
--dev
enables dev mode--config
provides the path to your YAML configuration file--supergraph
provides the path to your supergraph schema
sh./router --dev --config router.yaml --supergraph supergraph.graphql
About dev modeRunning router with--dev
is the same as using the following configuration:Learn more about router dev mode.YAMLSame configuration as --dev1sandbox: 2 enabled: true 3homepage: 4 enabled: false 5supergraph: 6 introspection: true 7include_subgraph_errors: 8 all: true 9plugins: 10 # Enable with the header, Apollo-Expose-Query-Plan: true 11 experimental.expose_query_plan: true
Check that your router is running, with output similar to the example:
Example router outputsh2025-04-25T21:54:05.910202Z INFO Running with *development* mode settings which facilitate development experience (e.g., introspection enabled) 2025-04-25T21:54:05.981114Z INFO Apollo Router v2.1.3 // (c) Apollo Graph, Inc. // Licensed as ELv2 (https://go.apollo.dev/elv2) 2025-04-25T21:54:05.981141Z INFO Anonymous usage data is gathered to inform Apollo product development. See https://go.apollo.dev/o/privacy for details. 2025-04-25T21:54:05.985764Z INFO state machine transitioned event="UpdateLicense(Unlicensed)" state=Startup previous_state="Startup" 2025-04-25T21:54:05.987948Z INFO state machine transitioned event="UpdateConfiguration(<redacted>)" state=Startup previous_state="Startup" 2025-04-25T21:54:05.988144Z INFO state machine transitioned event="NoMoreLicense" state=Startup previous_state="Startup" 2025-04-25T21:54:06.010232Z INFO Health check exposed at http://127.0.0.1:8088/health 2025-04-25T21:54:06.010717Z WARN Connector debugging is enabled, this may expose sensitive information. 2025-04-25T21:54:06.405064Z INFO GraphQL endpoint exposed at http://127.0.0.1:5555/ 🚀 2025-04-25T21:54:06.405628Z INFO You're using some "experimental" features of the Apollo Router (those which have their configuration prefixed by "experimental_"). We may make breaking changes in future releases. To help us design the stable version we need your feedback. Here is a list of links where you can give your opinion: - experimental_response_trace_id: https://github.com/apollographql/router/discussions/2147 For more information about launch stages, please see the documentation here: https://www.apollographql.com/docs/resources/product-launch-stages/ 2025-04-25T21:54:06.406568Z INFO state machine transitioned event="UpdateSchema(<redacted>)" state=Running previous_state="Startup" 2025-04-25T21:54:06.406591Z INFO state machine transitioned event="NoMoreConfiguration" state=Running previous_state="Running"
5. Make a query
When the router runs in dev mode, it hosts an Apollo Sandbox automatically. Sandbox has a browser-based IDE, Explorer, that you can use to write and send real GraphQL queries to your graph.
Go to the URL your router is running at,
http://127.0.0.1:5555
. Sandbox should be running there.Copy and paste the example query into the Operation pane of Explorer:
GraphQL1query Query { 2 recommendedProducts { 3 inStock 4 name 5 price 6 reviews { 7 author { 8 name 9 } 10 } 11 } 12}
Click Query to run the query, then check for its response in the Response pane.
That's it! You've successfully sent a query to a router running a development graph and received a response.
Next steps
Now that you've run the router locally, explore more about deployment and configuration:
Deploy the router in your own infrastructure with containers and/or Helm.
Configure runtime features of the router.