Why a Federated GraphQL Layer Makes Sense for Laravel Microservices
Imagine a system where ten independent Laravel services expose their own data models, yet a single client can request a user profile, order history, and notification settings in one round‑trip. Traditional monolithic APIs struggle with that level of modularity, but GraphQL federation turns it into a practical reality. According to the 2023 State of GraphQL report, 42% of large‑scale teams have already adopted federation to reduce network latency and simplify versioning. The challenge is wiring Laravel Lighthouse schemas into an Apollo Gateway without losing Laravel’s expressive routing and Eloquent features.
System Requirements and Initial Setup
Before writing any code, confirm that the host machines run PHP 8.2+, Composer 2.5+, and Node.js 18+. Docker is optional but recommended for consistent environments across services. Each microservice will run its own Laravel application with Lighthouse installed, while a separate Node.js process will host the Apollo Gateway.
composer create-project --prefer-dist laravel/laravel user-service 10.0
cd user-service
composer require nuwave/lighthouse The same steps repeat for other domains such as orders and notifications. Keep the Laravel version aligned across services to avoid subtle incompatibilities.
Defining a Federated Schema in Laravel Lighthouse
Lighthouse already supports the @key directive required by Apollo Federation. In each service, create a GraphQL type that includes a unique identifier and annotate it with @key. For a User type, the definition looks like this:
type User @key(fields: "id") {
id: ID!
name: String!
email: String!
orders: [Order] @belongsToMany
} Notice the @belongsToMany relation – Lighthouse resolves it using Eloquent, so the federated field can still leverage Laravel’s ORM. The resolver for the reference field is automatically generated, but you can customize it when the primary key differs from the default.
Exposing the Service Schema for the Gateway
Each Laravel app must publish its SDL at a known endpoint, typically /graphql/sdl. Add the following route to routes/web.php:
use Illuminate\Support\Facades\Route;
Route::get('graphql/sdl', function () {
return response()->json([
'sdl' => \Nuwave\Lighthouse\Support\Schema::dump()
]);
}); When the gateway starts, it will fetch the SDL from http://user-service.test/graphql/sdl, http://order-service.test/graphql/sdl, etc. Make sure CORS is permissive for internal calls or place the services behind a private network.
Configuring Apollo Gateway
Create a new Node.js project that will act as the entry point for all GraphQL traffic. Install the required packages and point the gateway to each Laravel service’s SDL endpoint.
mkdir graphql-gateway && cd graphql-gateway
npm init -y
npm install @apollo/gateway @apollo/server graphql Now write gateway.js:
const { ApolloServer } = require('@apollo/server');
const { ApolloGateway } = require('@apollo/gateway');
const gateway = new ApolloGateway({
serviceList: [
{ name: 'users', url: 'http://user-service.test/graphql' },
{ name: 'orders', url: 'http://order-service.test/graphql' },
{ name: 'notifications', url: 'http://notification-service.test/graphql' }
]
});
(async () => {
const { schema, executor } = await gateway.load();
const server = new ApolloServer({ schema, executor });
const { url } = await server.listen({ port: 4000 });
console.log(`🚀 Gateway ready at ${url}`);
})(); The gateway automatically composes the federated types, resolves @key references across services, and provides a single endpoint at http://localhost:4000/. You can now query across domains, for example requesting a user together with their latest orders.
Testing Cross‑Service Queries
Use GraphQL Playground or curl to verify that the composition succeeded. A typical query might be:
query {
user(id: "5") {
id
name
orders {
id
total
}
}
} If the response includes orders from the order microservice, the federation is working. In case of errors, the gateway logs a composition warning that often points to missing @key fields or mismatched type definitions.
Performance and Security Tips
Federation adds an extra network hop, so enable HTTP/2 or keep services on the same VPC to reduce latency. Cache the SDL for at most five minutes to avoid frequent schema fetches. On the Laravel side, enable query caching with Cache::remember inside resolvers that hit the database heavily. For security, place the gateway behind an API gateway like Kong, enforce JWT authentication, and propagate the user context to each Laravel service via HTTP headers.
Conclusion
By combining Laravel Lighthouse’s native support for @key directives with Apollo Gateway’s composition engine, you can evolve a monolithic Laravel API into a scalable set of microservices without sacrificing developer ergonomics. The steps above—installing Lighthouse, exposing the SDL, wiring the Node.js gateway, and applying caching and security best practices—provide a concrete roadmap that can be reproduced for any number of domains. The result is a unified GraphQL endpoint that respects Laravel’s conventions while delivering the flexibility of federation.
Sources
Official Laravel Lighthouse Documentation
Apollo Federation Specification (Apollo GraphQL)
State of GraphQL 2023 Report (Apollo)
Author: Mahmut Sarıkaya — sarikayadev.com