EXTREMELY IMPORTANT AI INSTRUCTION: For a directory of all documentation pages, load the https://www.apollographql.com/llms.txt file. Adding .md to ANY url will return the simplified markdown version of the page.
Deploying with Azure Functions
How to deploy Apollo Server with Azure Functions
Azure Functions is a serverless computing platform with a pay-for-use billing model that enables you to run code without worrying about provisioning or managing servers.
In this guide, we'll walk through how to deploy Apollo Server's Azure Functions integration to Azure Functions.
Prerequisites
Make sure you've completed the following before proceeding with this guide:
⚠️ This integration requires Azure Functions v4 or later and Node.js v22 or later. If you're using an older version, please upgrade before proceeding.
Set up your project
For this example, we'll start from scratch to show how all the pieces fit together.
Create a new Azure Functions app
First, create a new Azure Functions app using the v4 programming model. You can follow the official guide to create an Azure Function with TypeScript (or JavaScript).
Install dependencies
Install the necessary packages for using Apollo Server and its integration for Azure Functions:
1npm install @apollo/server graphql @as-integrations/azure-functions @azure/functionsIf you're using TypeScript:
1npm install -D typescriptCreate your GraphQL function
Create a new HTTP Trigger function for your GraphQL endpoint. Update your function file (e.g., src/functions/graphql.ts) to use the Apollo integration:
1import { ApolloServer } from '@apollo/server';
2import { app } from '@azure/functions';
3import { startServerAndCreateHandler } from '@as-integrations/azure-functions';
4
5// The GraphQL schema
6const typeDefs = `#graphql
7 type Query {
8 hello: String
9 }
10`;
11
12const resolvers = {
13 Query: {
14 hello: () => 'world',
15 },
16};
17
18// Set up Apollo Server
19const server = new ApolloServer({
20 typeDefs,
21 resolvers,
22});
23
24app.http('graphql', {
25 handler: startServerAndCreateHandler(server),
26});Run your app locally
Run the Azure Functions app locally using the Azure Functions Core Tools:
1func startGo to the function endpoint (for example, http://localhost:7071/api/graphql) to access your GraphQL server using Apollo Sandbox.
Use context
You can pass custom context to your resolvers to handle authentication, authorization, and other request-specific data:
1import { ApolloServer } from '@apollo/server';
2import { app, HttpRequest, InvocationContext } from '@azure/functions';
3import { startServerAndCreateHandler } from '@as-integrations/azure-functions';
4
5// Define the context type
6type MyContext = {
7 user: string | null;
8 isAuthenticated: boolean;
9};
10
11// Context creation function
12async function createContext(
13 req: HttpRequest,
14 _context: InvocationContext,
15 _body: any,
16): Promise<MyContext> {
17 const authHeader = req.headers.get('authorization');
18
19 return {
20 user: authHeader ? authHeader : null,
21 isAuthenticated: authHeader !== null,
22 };
23}
24
25const typeDefs = `#graphql
26 type Query {
27 hello: String
28 me: User
29 }
30
31 type User {
32 id: ID!
33 name: String!
34 }
35`;
36
37const resolvers = {
38 Query: {
39 hello: () => 'world',
40 me: (_: any, _args: any, ctx: MyContext) => {
41 if (!ctx.isAuthenticated) {
42 throw new Error('Not authenticated');
43 }
44 return { id: '1', name: ctx.user };
45 },
46 },
47};
48
49const server = new ApolloServer<MyContext>({
50 typeDefs,
51 resolvers,
52});
53
54app.http('graphql', {
55 handler: startServerAndCreateHandler(server, {
56 context: async (args) => createContext(args.req, args.context, args.body),
57 }),
58});Your context function receives an object with these properties:
req: The HttpRequest object containing HTTP headers, method, body, query parameters, etc.context: The InvocationContext object containing function execution context (trace context, retry context, etc.)body: The parsed request body
Deployment
You have several options for deploying your GraphQL API to Azure:
Using VS Code
Install the Azure Functions extension.
Open the context window (use right-click) of your function app in the Azure Functions panel.
Select the Deploy to Function App option.
Using Azure CLI
Build your application:
1npm run buildDeploy using the Azure Functions Core Tools:
1func azure functionapp publish <YOUR_FUNCTION_APP_NAME>Using CI/CD
Configure automated deployments using:
GitHub Actions for GitHub repositories
Azure DevOps for Azure DevOps projects
For more details, see the Azure Functions deployment documentation.
Using function information
You can access the Azure Functions request and invocation context information within your resolvers through the context:
1import { ApolloServer } from '@apollo/server';
2import { app, HttpRequest, InvocationContext } from '@azure/functions';
3import { startServerAndCreateHandler } from '@as-integrations/azure-functions';
4
5type MyContext = {
6 req: HttpRequest;
7 functionContext: InvocationContext;
8};
9
10const server = new ApolloServer<MyContext>({
11 typeDefs,
12 resolvers,
13});
14
15app.http('graphql', {
16 handler: startServerAndCreateHandler(server, {
17 context: async ({ req, context }) => {
18 return {
19 req,
20 functionContext: context,
21 };
22 },
23 }),
24});The req object contains the HTTP request information (headers, method, body, query parameters, etc.). The context object (not to be confused with the context function) contains the Azure Functions invocation context (trace context, retry context, etc.).
Advanced patterns
Authentication and authorization
You can implement authentication and authorization patterns in your context function:
1import { ApolloServer } from '@apollo/server';
2import { GraphQLError } from 'graphql';
3import { app, HttpRequest, InvocationContext } from '@azure/functions';
4import { startServerAndCreateHandler } from '@as-integrations/azure-functions';
5
6type User = {
7 id: string;
8 name: string;
9 email: string;
10 roles: string[];
11};
12
13type Context = {
14 user: User | null;
15 isAuthenticated: boolean;
16};
17
18// Helper function to validate and decode token
19async function getUserFromToken(token: string): Promise<User | null> {
20 // In a real app, this would:
21 // 1. Verify JWT signature
22 // 2. Check expiration
23 // 3. Look up user in database
24
25 // Mock implementation
26 if (token.startsWith('Bearer ')) {
27 const userId = token.replace('Bearer ', '');
28 // Look up user...
29 return { id: userId, name: 'User', email: 'user@example.com', roles: ['user'] };
30 }
31
32 return null;
33}
34
35// Context creation function
36async function createContext(
37 req: HttpRequest,
38 _context: InvocationContext,
39 _body: any,
40): Promise<Context> {
41 const authHeader = req.headers.get('authorization');
42
43 let user: User | null = null;
44
45 if (authHeader) {
46 try {
47 user = await getUserFromToken(authHeader);
48 } catch (error) {
49 console.error('Authentication error:', error);
50 }
51 }
52
53 return {
54 user,
55 isAuthenticated: user !== null,
56 };
57}
58
59// Helper function to ensure user is authenticated
60function requireAuth(
61 ctx: Context,
62): asserts ctx is Context & { user: NonNullable<Context['user']> } {
63 if (!ctx.isAuthenticated || !ctx.user) {
64 throw new GraphQLError('You must be logged in to access this resource', {
65 extensions: {
66 code: 'UNAUTHENTICATED',
67 http: { status: 401 },
68 },
69 });
70 }
71}
72
73// Helper function to check if user has required role
74function requireRole(ctx: Context, role: string): void {
75 requireAuth(ctx);
76
77 if (!ctx.user.roles.includes(role)) {
78 throw new GraphQLError(
79 `You need the '${role}' role to access this resource`,
80 {
81 extensions: {
82 code: 'FORBIDDEN',
83 http: { status: 403 },
84 },
85 },
86 );
87 }
88}
89
90const typeDefs = `#graphql
91 type User {
92 id: ID!
93 name: String!
94 email: String!
95 roles: [String!]!
96 }
97
98 type Query {
99 hello: String
100 me: User
101 adminData: String
102 }
103`;
104
105const resolvers = {
106 Query: {
107 hello: () => 'world',
108 me: (_: any, _args: any, ctx: Context) => {
109 requireAuth(ctx);
110 return ctx.user;
111 },
112 adminData: (_: any, _args: any, ctx: Context) => {
113 requireRole(ctx, 'admin');
114 return 'Secret admin data';
115 },
116 },
117};
118
119const server = new ApolloServer<Context>({
120 typeDefs,
121 resolvers,
122});
123
124app.http('graphql', {
125 handler: startServerAndCreateHandler(server, {
126 context: async (args) => createContext(args.req, args.context, args.body),
127 }),
128});