API Reference: startStandaloneServer


This API reference documents the startStandaloneServer function.

Overview

This startStandaloneServer function helps you get started with Apollo Server quickly. This function is recommended for prototyping. For production services, we recommend integrating Apollo Server with a more fully-featured web framework such as Express, Koa, or Fastify.

You can find a list of supported web frameworks in web framework integrations. For an example migration path, see Swapping to expressMiddleware.

startStandaloneServer

In the examples below, we use top-level await calls to start our server asynchronously. Check out our Getting Started guide to see how we configured our project to support this.

The startStandaloneServer function accepts two arguments. The first required argument is the instance of ApolloServer to begin listening for incoming requests:

TypeScript
1import { ApolloServer } from '@apollo/server';
2import { startStandaloneServer } from '@apollo/server/standalone';
3
4const server = new ApolloServer({ typeDefs, resolvers });
5
6// `startStandaloneServer` returns a `Promise` with the
7// the URL that the server is listening on.
8const { url } = await startStandaloneServer(server);

The startStandaloneServer function's second optional argument is an object for configuring your server's options, which can contain the following properties:

Options

Name /
Type
Description
context
Function
An optional asynchronous context initialization function.
The context function should return an object that all your server's resolvers share during an operation's execution. This enables resolvers to share helpful context values, such as a database connection.
The context function receives req and res options which are http.IncomingMessage and http.ServerResponse types. (In Apollo Server 4, these happen to be implemented using Express's subclasses which have some extra Express-provided functionality, though this was an undocumented fact that users should not have relied on. In Apollo Server 5, the standalone server is not built on Express; if you need to use Express-specific request/response functionality, swap to expressMiddleware.)
listen
Object
An optional listen configuration object. The listen option accepts an object with the same properties as the net.Server.listen options object.
If no port is specified, this defaults to using {port: 4000}.

Example

Below is a full example of setting up startStandaloneServer:

TypeScript
1import { ApolloServer } from '@apollo/server';
2import { startStandaloneServer } from '@apollo/server/standalone';
3import { typeDefs, resolvers } from './schema';
4
5interface MyContext {
6  token?: String;
7}
8
9
10const server = new ApolloServer<MyContext>({ typeDefs, resolvers });
11const { url } = await startStandaloneServer(server, {
12  context: async ({ req }) => ({ token: req.headers.token }),
13  listen: { port: 4000 },
14});
15console.log(`🚀  Server ready at ${url}`);

Swapping to expressMiddleware

The startStandaloneServer function is not right for every use case, particularly if you need to customize your server's behavior. For example, you might want to customize your CORS behavior, run some middleware before processing GraphQL requests, or serve other endpoints from the same server.

In these cases, we recommend you swap out startStandaloneServer for expressMiddleware (unless you are confident that you want to use a different Node.js framework). This change requires only a few lines and has a minimal effect on your server's existing behavior (startStandaloneServer uses expressMiddleware under the hood).

We recommend Express because it's the most popular Node.js web framework, and it integrates well with many other popular libraries.

Example

Let's say our current startStandaloneServer setup uses the following code:

TypeScript
1import { ApolloServer } from '@apollo/server';
2import { startStandaloneServer } from '@apollo/server/standalone';
3import { typeDefs, resolvers } from './schema';
4
5interface MyContext {
6  token?: String;
7}
8
9const server = new ApolloServer<MyContext>({ typeDefs, resolvers });
10const { url } = await startStandaloneServer(server, {
11  context: async ({ req }) => ({ token: req.headers.token }),
12  listen: { port: 4000 },
13});
14console.log(`🚀  Server ready at ${url}`);

To swap to using expressMiddleware, you'll first need to install the following packages: the Express library, Apollo's integration between Express and Apollo Server, and the CORS middleware for Express:

Bash
1npm install @as-integrations/express5 express cors

Note that this should install v5 of Express.

Next, we can modify our code to match the following:

TypeScript
1import { ApolloServer } from '@apollo/server';
2import { expressMiddleware } from '@as-integrations/express5';
3import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer';
4import express from 'express';
5import http from 'http';
6import cors from 'cors';
7import { typeDefs, resolvers } from './schema';
8
9interface MyContext {
10  token?: String;
11}
12
13// Required logic for integrating with Express
14const app = express();
15// Our httpServer handles incoming requests to our Express app.
16// Below, we tell Apollo Server to "drain" this httpServer,
17// enabling our servers to shut down gracefully.
18const httpServer = http.createServer(app);
19
20// Same ApolloServer initialization as before, plus the drain plugin
21// for our httpServer.
22const server = new ApolloServer<MyContext>({
23  typeDefs,
24  resolvers,
25  plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
26});
27// Ensure we wait for our server to start
28await server.start();
29
30// according to RFC8259, only UTF-8 is allowed in JSON text
31// (see https://datatracker.ietf.org/doc/html/rfc8259#section-8.1)
32// RFC 7159 also specifies that JSON could be UTF-16 or UTF-32,
33// so we allow for that, too
34const validCharset = /^utf-(8|((16|32)(le|be)?))$/i;
35
36// Set up our Express middleware to handle CORS, body parsing,
37// and our expressMiddleware function.
38app.use('/',
39  cors<cors.CorsRequest>(),
40  express.json({
41    verify(req) {
42      const charset = parseContentType(req).parameters.charset || 'utf-8';
43      if (!charset.match(validCharset)) {
44        throw Object.assign(
45          new Error(`unsupported charset "${charset.toUpperCase()}"`),
46          {
47            status: 415,
48            name: 'UnsupportedMediaTypeError',
49            charset,
50            type: 'charset.unsupported',
51          },
52        );
53      }
54    },
55    // 50mb is the limit that `startStandaloneServer` uses to cover all possible bases, but you may configure this to suit your needs.
56    // Generally we recommend keeping this as small as possible to still suit your use case.
57    // The `body-parser` default is '100kb'.
58    // limit: '50mb',
59  }),
60  // expressMiddleware accepts the same arguments:
61  // an Apollo Server instance and optional configuration options
62  expressMiddleware(server, {
63    context: async ({ req }) => ({ token: req.headers.token }),
64  }),
65);
66
67// Modified server startup
68await new Promise<void>(resolve => httpServer.listen({ port: 4000 }, resolve));
69console.log(`🚀 Server ready at http://localhost:4000/`);
Feedback

Edit on GitHub

Ask Community