Why combine Laravel with Dapr for microservices?
Imagine a Laravel application that can call a Go service, listen to Kafka events, and persist user sessions in Redis without writing custom adapters for each technology. Dapr (Distributed Application Runtime) makes this scenario realistic by providing language‑agnostic building blocks that sit beside your code. The result is a polyglot microservice landscape where Laravel remains the familiar MVC framework while Dapr handles cross‑language communication, reliable messaging, and state management.
System requirements and preparation
Before diving in, ensure your development machine runs Docker Engine 20.10+ and has at least 4 GB of RAM. Laravel 10 (PHP 8.2) is recommended, and Dapr CLI version 1.12 or newer should be installed globally (brew install dapr-cli on macOS or winget install dapr on Windows). Create a fresh Laravel project with composer create-project --prefer-dist laravel/laravel dapr-demo. After the project scaffolds, add the official Dapr PHP SDK:
composer require dapr/dapr-sdk-phpService invocation with Laravel
Service invocation lets one microservice call another via HTTP or gRPC, abstracting away URL construction and retry logic. In Dapr, each service registers a app‑id. Suppose you have a payment service written in Node.js with app‑id payment-service. From Laravel you can invoke its /process endpoint like this:
use Dapr\Client\DaprClient;\n\n$client = new DaprClient();\n$response = $client->invokeMethod(\
"payment-service", // target app-id\n "process", // method name\n "POST", // HTTP verb\n [\"order_id\" => 12345, \"amount\" => 99.99]\n);\n\nif ($response->getStatusCode() === 200) {\n $result = json_decode($response->getBody(), true);\n // handle successful payment\n}\nThe SDK automatically adds the Dapr sidecar address (http://localhost:3500) and retries on transient failures. You can also switch to gRPC by passing "grpc" as the fourth argument, which reduces latency for high‑throughput scenarios.
Pub/Sub integration
Dapr’s publish/subscribe model decouples producers from consumers. Laravel can act as both a publisher and a subscriber without dealing with Kafka, RabbitMQ, or Azure Service Bus directly. First, declare a Pub/Sub component in components/pubsub.yaml:
apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: rabbitmq-pubsub\n namespace: default\nspec:\n type: pubsub.rabbitmq\n version: v1\n metadata:\n - name: host\n value: "amqp://guest:guest@localhost:5672"\nRun the Dapr sidecar with the component folder mounted: dapr run --app-id laravel-app --app-port 8000 --components-path ./components php artisan serve. To publish an event from a controller:
use Dapr\Client\DaprClient;\n\npublic function orderCreated(Request $request) {\n $client = new DaprClient();\n $event = [\"order_id\" => $request->input('id'), \"status\" => 'created'];\n $client->publishEvent(\"rabbitmq-pubsub\", \"order-events\", $event);\n return response()->json(['message' => 'Event published']);\n}\nOn the subscriber side, Dapr forwards messages to an HTTP endpoint defined by the topic annotation. Add a route in routes/web.php:
use Illuminate\Support\Facades\Route;\n\nRoute::post('/dapr/subscription/order-events', function (\Illuminate\Http\Request $request) {\n $payload = $request->all();\n // Persist order status, trigger notifications, etc.\n return response()->json(['status' => 'processed']);\n});\nFinally, expose the subscription metadata so Dapr knows which topics to bind:
use Dapr\App\Subscription;\n\nreturn [\n Subscription::topic('order-events')\n ->setPubsubName('rabbitmq-pubsub')\n ->setRoute('/dapr/subscription/order-events')\n];\nThis declarative approach means you can add new consumers in Python or .NET simply by registering the same topic.
State stores for durable Laravel data
State stores give you a key‑value abstraction that survives restarts and can be replicated across regions. Dapr supports Redis, Azure Cosmos DB, MySQL, and more. To store a user’s shopping cart in Redis, define a state component:
apiVersion: dapr.io/v1alpha1\nkind: Component\nmetadata:\n name: redis-state\n namespace: default\nspec:\n type: state.redis\n version: v1\n metadata:\n - name: redisHost\n value: "localhost:6379"\n - name: redisPassword\n value: ""\nIn a Laravel service class, interact with the state store:
use Dapr\Client\DaprClient;\n\nclass CartService {\n protected DaprClient $client;\n public function __construct() {\n $this->client = new DaprClient();\n }\n public function addItem(string $userId, array $item) {\n $key = "cart-{$userId}";\n $state = $this->client->getState('redis-state', $key);\n $cart = $state ? json_decode($state, true) : [];
$cart[] = $item;\n $this->client->saveState('redis-state', $key, json_encode($cart));\n }\n public function getCart(string $userId) {\n $key = "cart-{$userId}";\n $state = $this->client->getState('redis-state', $key);\n return $state ? json_decode($state, true) : [];
}\n}\nThe SDK handles serialization and retries, and you can enable strong consistency by setting the concurrency and consistency options in the component definition.
Putting it all together: a minimal polyglot workflow
Consider an e‑commerce checkout flow: the front‑end (React) calls a Laravel API to create an order, Laravel publishes order-events, the Go‑based inventory service subscribes, updates stock, and invokes the Laravel payment service via Dapr. Once payment succeeds, the Laravel service stores the order state in Redis. All communication is mediated by Dapr, so each language team works independently while sharing the same runtime contracts.
Key practical tips: keep component definitions version‑controlled alongside your code, use Dapr’s built‑in observability (metrics on http://localhost:9090/metrics) to monitor latency, and enable sidecar health checks in Kubernetes deployments to guarantee zero‑downtime upgrades.
Conclusion
Leveraging Dapr with Laravel transforms a monolithic PHP codebase into a resilient, polyglot microservice ecosystem. Service invocation removes hard‑coded URLs, Pub/Sub decouples event producers and consumers, and state stores give you portable, consistent storage without locking into a single database vendor. By adopting the patterns described above, Laravel teams can confidently expand their architecture to include services written in any language while preserving the developer experience they love.
Author: Mahmut Sarıkaya — sarikayadev.com
Sources
Official Dapr Documentation; Laravel Official Documentation; Dapr PHP SDK GitHub Repository