This is my first article on Medium, and it was created for a very specific reason: “I have to make this research anyway, so why don’t share with everyone?”. Also, there is a long time that I was planning to start writing stuff here, but never found time to really do it. So I got the opportunity now.
I always asked myself what is the real difference between those two siblings frameworks, and if really worths to give up from some features that just the big brother (Laravel) have, in exchange of a speed boost with the small brother (Lumen). I think that “how much speed?” is the big question. The goal here is not to bring a final decision, but bring some information to the table, so the reader can judge it and take the decision. Of course, there are no absolute responses here, since it’s extremely dependent on the project needs.
First of all, let’s clarify what we’re comparing. If you’re building an MVC website/system, that needs to render pages directly using templates, and keep state information on sessions, there is no discussion: You can only go with Laravel. Simply because Lumen doesn’t support those things. Lumen was build to support stateless APIs (that are also supported by Laravel). So we’ll only compare what both frameworks can do (serve stateless APIs).
Before starting with comparisons, let’s quickly define the biggest differences between the frameworks, quickly comment each one (pros and cons) and at the end compare them with benchmarks (just the benchmarks that make sense. You’ll understand what I’m saying).
Difference 1 — View templating engine
This is the most known and commented difference. Laravel uses Blade for templating (and it’s an awesome templating tool), and Lumen just don’t have a templating engine.
I’m not considering this difference in the comparison, because if we’re using Laravel to serve a stateless API, there is no templating at all. The engine will be there, but we’ll just not use it (what is not a big problem).
Difference 2 — Session engine
Lumen doesn’t have any mechanism to handle sessions since it’s designed to work in a stateless way. Laravel has a powerful Session manager.
Again, not a big problem, since we’re building a stateless API, and the Session engine from Laravel will be completely deactivated (same as templating).
Difference 3 — Routing
Here we have a real difference! Laravel routing mechanism is REALLY powerful. It allows you to create resource routes (creating all the routes for a CRUD operation at once), and automatically bind Eloquent models to variables based on values passed on the route (and it take care of returning the error messages when a resource is not found). It gives the developer the ability to keep the controller's code extremely clean and elegant. The definition of the routes itself is pretty elegant. Laravel router also supports route caching, that significantly improves the speed of the routing. Of course, all this awesomeness have a price. Laravel routing mechanism (even with cache enabled) is not that fast, and that’s why Lumen was packed with a simpler, but faster third party router. Lumen router doesn’t support automatically model binding (what is the biggest downside in my opinion), neither supports caching (what it’s not a big problem since it’s still faster). I’ll not discuss the elegance of the route definition since it’s just syntax sugar.
The question here is, we’re giving up a nice feature (automatic model binding) in exchange of speed. This way, we need to think if the speed gains worths the loose of this feature. We’ll let this discussion for the benchmarks.
Difference 4 — Form Request
Form requests are structures used by Laravel to represent the body of a request, and hold the validation logic of it. It was designed initially to mirror HTML forms (that’s why the name is Form request), but it can be used for any request (including REST request bodies). Those structures take care of the validation, returning validation error responses when it fails (error code, response payload, error messages). Everything before hitting the controller. All you have to do is to type-hint the request variable to the form request class. Also, Laravel doesn’t have a sanitizing engine embedded, but you can easily extend it with third-party libraries providing the sanitize feature for requests in addition to validation. This way you can trust that every data that hit your controller is valid, what makes your controller code EXTREMELY clean (You’ll see that on the code comparison).
Lumen doesn’t support Form Requests, and it’s linked to the router difference that I showed above (it can’t bind the request body automatically to a form request). All the validation and sanitization of data need to go inside the controller.
Difference 5 — Eloquent
Both frameworks support Eloquent (the Laravel’s ORM engine), but only on Lumen, it’s possible to completely disable it (it’s disabled by default).
This is a complex discussion. When you talk about MVC frameworks, ORM is an extremely coupled matter. Usually, when you use an MVC framework, you want ORM, because it is one of the biggest sources of the agility that you won with MVC. Of course, sending selects directly to the database is more performant than using an ORM engine. But you really want to manually handle all the relationships, casts and everything that comes with it? Do you want to take the risks of having it on your responsibility? How about maintenance?
The fact is, in most cases, even with Lumen, you’ll want to use Eloquent because without Eloquent the framework turns from a bazooka into a pistol. It just looses most of the power. It’s also important to say that Eloquent is one of the pieces of Laravel that was completely rewritten from scratch because the ORM engine from Symfony (based on Doctrine) was extremely slow (yeah! Laravel is based on Symfony, and uses many Symfony components under the hood).
Difference 6 — Facades
Facades are similar to Eloquent on this comparison. Both frameworks support it, but only Lumen gives you the ability to completely disable it, and it’s disabled by default.
But here we have a concept misunderstood most of the times. Facades is a design pattern (I’m not going into the Facade concept here). What you disable in Lumen, in fact, are the facades classes and the global aliases that Laravel conveniently gives to the developer to easily access some modules (like Log, Auth, etc). But you still can use the app() helper function, passing the facade accessor as a parameter (what is exactly the same).
In fact, if you want to use Laravel without facades, you can just remove all the aliases definitions, and always use the app() helper function. You’re not disabling it, but it’s not using it, what in the end is the same.
From the performance point of view, is really hard to say if using facades really harm the performance, because you need heavy use of this structure to make difference, what is not true on a benchmark application.
Difference 7 — Artisan Generators
Artisan is the command-line tool for Laravel and Lumen. Both use the same structure. But Laravel has much more commands available than Lumen.
A good example is generators. On Laravel, you have “make” commands to generate basically any structure on the code. On Lumen you have to do that copying and pasting it from an example file. Not fancy at all.
But the big question here is that artisan just don’t affect the execution time of requests, and that said, I really don’t understand why Lumen artisan was packed as a dehydrated version of Laravel artisan.
It doesn’t cause any difference in API performance, but we need to register that it’s a downside of Lumen.
Extra - Community, support, third-party libraries
Laravel and Lumen basically share the same community, but it’s clear that Laravel is more popular. Because of that, it’s easy to find help online (easier than Lumen). Also, the number of components built for Laravel is considerably bigger than the ones built for Lumen. Usually, the biggest components (like Passport, Socialite, Debugbar, etc) are packed both for Laravel and Lumen, but Lumen version is always an adapted version of Laravel component.
I set up 4 tiny projects. Two of them are fresh installs of Lumen and Laravel. The unique change on Laravel is that I included a route that just returns the application version, on the API routes file (just like Lumen do). On those fresh projects, Lumen config is kept as default (no Eloquent, no Database access, no Facades).
The other two projects are both a little API, that has the CRUD operations for one entity (customer). This entity has 3 required fields: first_name, last_name and email (email is required to be a valid email). The projects were build using Laravel and Lumen. On this project eloquent is enabled on Lumen (we need database access). On Laravel we removed entirely the views and all the routes, middlewares and service providers that are not needed for a stateless API.
On all projects, all the possible/available tunning actions were made (caching routes and config on Laravel).
The source code can be downloaded here.
Enough talking, here are the results:
As you can see, there is a huge performance difference between the fresh installs. Lumen really kicks Laravel ass. And this is the comparisons that you’ll see all over the internet. People will repeat the mantra: “Lumen is at least 4 times faster than Laravel, so if you want an API, use Lumen”.
But looking deeper, on closer to a real-world application (that accesses a database and do more than just return a string), we see that the difference is not so big (sometimes there is no practical difference at all). We see that requests that use form requests, the difference is bigger (maybe there’s why Lumen developers decided to keep this feature out), but still, the difference is not so big. Thinking that a real application will probably spend much more time getting data from the database, this difference can be even smaller.
This piece of text is just my opinion and not a definitive answer to the question on the title of this article.
In my opinion, Laravel and Lumen are great. Both are the best on what they were created to do. Lumen is a micro-framework, made to support micro-services. Laravel was made to support big systems (not just web sites, but also web APIs). Both are just frameworks (tools), so it’s up to the developer to make them work in the best way. I don’t think that a Rest API with dozens of endpoints, that powers the backend of an entire system is a microservice. Rest API and micro-services aren’t synonymous.
So, if you’re building a tiny API (with a few endpoints) to serve a specific purpose, use Lumen. If you call what you’re building a system, I would go with Laravel.