In modern micro‑frontend and micro‑service environments, GraphQL Federation with Apollo Server 4 in Nx monorepo offers a clean way to stitch multiple GraphQL services into a single unified API. This guide walks you through the entire process, from initializing an Nx workspace to exposing a federated gateway, all written in TypeScript.
Why choose GraphQL Federation with Apollo Server 4 in an Nx monorepo?
Federation enables independent teams to own their schemas while presenting a single endpoint to consumers. Combining it with Nx gives you powerful build caching, affected‑project detection, and consistent TypeScript tooling across services.
Prerequisites and Nx workspace setup
Before diving in, make sure you have the following installed:
- Node.js 20 LTS
- npm 9 or Yarn 4
- npx (bundled with Node)
- Git for version control
Run the commands below to create a new Nx workspace tailored for TypeScript:
npx create-nx-workspace@latest federated‑api
--preset=empty
--npmScope=company
--style=none
--packageManager=npm
cd federated‑api
npm install -D typescript @nrwl/node @nrwl/react @nrwl/express
Enable the @nrwl/graphql plugin (experimental) to simplify GraphQL code generation:
npm install -D @nrwl/graphql graphql
Creating the first federated service – User service
Inside the monorepo, generate a Node library that will host the User service:
npx nx g @nrwl/node:library user-service --publishable --importPath=@company/user-service
Install Apollo Server 4 and federation utilities:
npm install apollo-server@4 @apollo/subgraph graphql
Define the federated schema
Create libs/user-service/src/schema.ts with the following content:
import { gql } from 'graphql-tag';
export const typeDefs = gql`
extend type Query {
me: User @shareable
}
type User @key(fields: "id") {
id: ID!
name: String!
email: String!
}
`;
Resolver implementation
Implement resolvers that respect the @key directive for entity reference:
export const resolvers = {
Query: {
me: () => ({ id: '1', name: 'Jane Doe', email: 'jane@company.com' })
},
User: {
__resolveReference(user: { id: string }) {
// In a real app, fetch from DB by ID
return { id: user.id, name: 'Jane Doe', email: 'jane@company.com' };
}
}
};
Expose the service with Apollo Server
Update libs/user-service/src/main.ts:
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
import { buildSubgraphSchema } from '@apollo/subgraph';
import { typeDefs, resolvers } from './schema';
const server = new ApolloServer({
schema: buildSubgraphSchema({ typeDefs, resolvers })
});
startStandaloneServer(server, { listen: { port: 4001 } }).then(({ url }) => {
console.log(`🚀 User service ready at ${url}`);
});
Configuring the Apollo Gateway
The gateway composes the federated schemas at runtime. Generate another Node application for the gateway:
npx nx g @nrwl/node:application gateway --publishable --importPath=@company/gateway
Install the gateway packages:
npm install @apollo/gateway apollo-server@4 graphql
Gateway bootstrap file
Create apps/gateway/src/main.ts with the following logic:
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
import { ApolloGateway } from '@apollo/gateway';
const gateway = new ApolloGateway({
// List each federated service endpoint
serviceList: [
{ name: 'user', url: 'http://localhost:4001' },
// Add additional services here
]
});
const server = new ApolloServer({
gateway,
// Required for federation
plugins: [{ async serverWillStart() { console.log('Gateway ready'); } }]
});
startStandaloneServer(server, { listen: { port: 4000 } }).then(({ url }) => {
console.log(`🚀 Gateway running at ${url}`);
});
Connecting everything inside the Nx monorepo
Leverage Nx’s affected commands so that only changed services are rebuilt. Add the following to nx.json:
{
"npmScope": "company",
"implicitDependencies": {
"gateway": ["user-service"]
},
"targetDefaults": {
"build": {
"dependsOn": ["^build"]
}
}
}
Now run the two services concurrently using npm-run-all or concurrently:
npm install -D concurrently
# package.json scripts
"scripts": {
"dev:user": "nx serve user-service",
"dev:gateway": "nx serve gateway",
"dev": "concurrently "npm run dev:user" "npm run dev:gateway""
}
Testing the federated schema
Open http://localhost:4000/graphql in Apollo Sandbox and run a query that spans services:
{
me {
id
name
email
}
}
The gateway resolves me from the User service, proving successful federation.
Production‑ready considerations
- Health checks: Expose
/healthzendpoints on each service and let the gateway retry on failures. - Schema caching: Enable Apollo’s built‑in schema‑registry or use
apollo-server-plugin-baseto reduce startup latency. - Versioning: Keep each federated service on its own Git branch; Nx’s affected graph helps with safe releases.
- Security: Apply JWT validation at the gateway level and forward the user context to sub‑services.
Conclusion
Implementing GraphQL Federation with Apollo Server 4 in Nx monorepo gives you a modular, type‑safe architecture that scales with team size. By following the steps above—setting up the workspace, creating federated services, wiring the gateway, and adding production safeguards—you’ll deliver a robust GraphQL API that’s easy to maintain and fast to evolve.
Ready to take it further? Add automated tests with jest‑graphql and integrate CI pipelines to catch schema breaking changes before they reach production.