In this guest blog Schalk Wepener, one of Payfast’s Senior Lead Developers, investigates the differences between Symfony and Laravel. While both are popular PHP frameworks used for web application development, it’s a contested debate amongst developers about which one comes out on top….until now.
The debate has been raging on for years, which is better: Symfony or Laravel?
Most of the arguments I’ve seen have to do with speed, documentation, ease of use, etc. Laravel is built with Symfony components, so a lot of people think it’s similar or even better. But I’ve always had my doubts.
My first experience with a proper framework was with Symfony, around 2010. At that point, I was writing PHP code in a semi-spaghetti fashioned way. We had a basic class generator that provided a skeleton for a model, the various views and repeaters. This you had to manually insert into the HTML as needed.
It was quick, easy and dirty, just the way the doctor ordered. In my eyes, it was great, as I could whip up a CRUD system in less than a day. During this time a friend of mine started talking about Symfony. He had experience with the Zend Framework at that time and various other bits and bobs. As we compared my code and working style to his using Symfony, it became clear to me I needed to try it out.
My very first attempt at using Symfony was the obligatory Car CRUD. Once I had my WAMP setup (yes, I used Windows for everything back then), the terminal opened and glancing over the “getting started” documentation, I started typing. Five minutes later, I had a car model, and the database table was created as per my wishes, indexes, relationship, and all. I was hooked.
Fast forward a couple of months, a new project came up and I decided to give Symfony a go in a production setting. I had to do a bit of minor convincing with the boss, but the objective was clear: deliver the project in the allotted time and you can use what you want. Project delivered and on to the next. An experiment started by reusing code in modules, such as the Users system, and the next project could be completed even faster. I was really loving Symfony and started to use it everywhere possible.
Fast forward a couple of years and a few jobs later, and I am introduced to Laravel. This new and amazing tool that is “similar” to Symfony. The community seems great, and everyone is talking highly of this tool, so I grabbed the opportunity to learn.
However, the very first thing I miss from Symfony is the CLI entity builder. This is strange! Why don’t they have this basic component that Symfony had years ago? In any case, I had some struggles but eventually, I got the hang of it, to such an extent that any piece of code I write for myself is Laravel based, professionally we run with Laravel as the backbone. But there was always the thing in the back of my mind that compared Symfony and Laravel.
For an upcoming project, re-writing of a legacy piece of software, thus blank canvas, the question was again asked which PHP framework to go with. Symfony jumped into my head once again and I put it forward. While reading up on the differences between Laravel and Symfony, I realised every article states that Laravel is faster than Symfony. That got me thinking, how do these people/companies test this? Perhaps I should put this to the test myself once and for all.
From that thought to this article series. Comparing Symfony and Laravel on various aspects. But the first is speed.
Which one is really faster?
The idea is simple: start up a virtual machine (Ubuntu, PHP, Apache … ), a normal everyday working environment. Setup both a Laravel and Symfony instance, get them to produce a basic Hello World and test them using a load balancing tool and document my various findings along the way.
Both frameworks will be tested with ‘out of the box’ setups, no optimisations, etc. This is to ensure we are comparing apples to apples. To help this along, the standard installation process will be followed as defined through the documentation.
I didn’t use Lumen during these tests as it’s not encouraged to use Lumen for new projects anymore. This is due to overall improvements in PHP and other optimisation tools. Read more about this here.
The process I was to follow during the tests is remarkably simple. Setup a test to run with K6 and execute it against both systems, record and analyse the data. Once that is done, adjust the test and do it over again. The tests will be adjusted in an upwards fashion / more (heavier) loads per run, so that we can see what happens during this progression.
All the building blocks are setup on the VM, this includes:
- Ubuntu 22
- Symfony global installer
- Laravel global installer
The Symfony installer comes with a requirement checker. This is a nice touch.
We also get a console command php `bin/console about` that produces an output indicating what
has been installed in the folder / project. I didn’t specify a version; thus, the installer automatically picked the latest stable release. This is just a skeleton to start working on an API. For a web application setup, you need to specify –web-app when running the installer.
After installation, you can start the webserver that is packaged inside the Symfony binary. This is a generic web server and can be used with any PHP project. It’s very interesting to note that Symfony does not come with a hello world page when installing the skeleton. The very first page you can access is a 404 page. Perhaps this follows the philosophy of being a skeleton with as little bloat as possible.
The Symfony installer seems to be kept up to date and the use of it is much more encouraged through the documentation.
Once you have the Laravel installer running, it will install the latest version of Laravel as well. Here you get a default welcome page. Laravel also supplies a web server through artisan (php artisan serve) and supplies an about command, same as Symfony. But it displays a bit more information.
Because I wanted to test both frameworks on equal terms, I created a standard Hello World in both. The routing for them was also set up in the exact same manner: /hello/world. Below you can see the controller code for both. I stripped everything I could, to keep it as small and simple as possible.
After the first test I also set up an API route, /api/hello/world, for Laravel. This is to see how Laravel performs on a dedicated API setup. In general, I know that returning HTML in an API is not really by the book, but this is the most basic way of comparing apples with apples, in the hello world context.
Round One: Hello World (speed)
The very first test
With both systems running within their respective web servers, I fired up K6 for the first time. This required a bit of reading and googling to get going, seeing that it was my first time using the tool, but I got it working. The script will be running 1 VU for 10 seconds.
So to set the scene: Both Symfony and Laravel are running on their own web server and responds to /hello/world
with a basic “Hello World” output. Nothing fancy.
Conclusion : Symfony runs faster!
To be fair, the Laravel /hello/world is running through the web.php router. Perhaps this is adding overhead to the overall performance.
It seems that Laravel struggles even more to keep up, by running with the API router. On this second test run, we can see that running through the API router, the average response time for Laravel is 21ms. The normal web router does the same task in an average of 13ms. But Symfony takes the win at 5ms.
Currently this doesn’t t look good for Laravel, in the speed category. This is interesting but let’s see how they perform running on a dedicated web server.
The Apache Runs
All the setups have been done and we are now ready to give this a bash. Within Apache we have two virtual hosts, one for Laravel and one for Symfony. They are accessible through http://laravel.bench and http://symfony.bench; please note no optimisations have been done at all. This is all just default installation and setup.
With everything set up, I ran a basic load test, utilising Apache to see how the systems perform on a dedicated web server. The test creates one virtual user and calls the end points constantly for 10 seconds
None of the systems dropped requests, which is very good, as in some of my previous hacks I managed to get Laravel to drop requests when Symfony kept going. Bearing in mind that this was before I had Apache setup properly and using the built-in web servers.
Symfony still out-performs Laravel easily, both the web and API route. The interesting thing here is that the API route is slower on average than the web route (15ms vs 14ms). Why is that? The minimum and medium speed measurements are remarkably close. But the maximum response time is again the same 37ms vs 24ms. The dedicated API route doesn’t do much in the greater scheme of things. Symfony on the other hand, comes in very close both times, 3.3ms vs 3.8ms. But it is a very big jump to 21ms with the maximum response time. So, if Symfony slows down it slows down!
Conclusion : Symfony is still faster!
Let us UP the ante.
In the next test, I decided to hit the system with more VUs but kept the duration the same. Here we are running 10 VUs for 10 seconds.
Now we start seeing the response times jump drastically. On the average mark Laravel API is better than Symfony, 384ms vs 518ms.
Conclusion : Laravel API is faster! Can it keep it up?
For this test we will hit the system with various amounts of VUs for varying amounts of time. In total we will have 40 VUs over a one-minute time span. The other difference with this test is that it didn’t start with VUs already connected, they will connect as required.
With these conditions, Symfony is again faster on average, 101ms. The Laravel API is 10ms faster than Laravel itself, 234ms vs 244ms. Looking at all the times, it seems that the API router is generally the faster one, for camp Laravel.
Conclusion : Symfony faster, again! Where has Laravel gone?
This is the same test as before, just more VUs and a longer time frame.
Again, Symfony is leading hands down, the API router of Laravel, slightly outperforms the web router. But nothing to write home about really.
Conclusion : Symfony is faster. The Laravel API router seems to have a place in the world?
With this test I went a bit mad and added more stages of varying VUs loads. The idea was to simulate spikes in the traffic, that will take the system to the max load and then to no load at all, before being hit again.
With these inconsistent loads, Symfony again performs better than Laravel. During the test, the Laravel API actually starts losing connections as well. This isn’t a very good sign.
Conclusion : Symfony handles better.
For this test, I opened the floodgates. I hit the systems with a total of 100 VUs over five minutes. Again, various amounts at various times and intervals. I just wanted to apply hurt to both systems to see what happens.
Symfony started to drop connections, only managing 99% success rate, the same as Laravel. The Laravel API on the other hand struggled to keep up. Only managing an 8% success rate. But still, on average, Symfony is faster.
Conclusion : Laravel does not have speed.
So, no matter how I ran the tests, Symfony performed better than Laravel, in terms of speed, in a basic Hello World test. The reason for this needs to be determined, but I think it comes from the fact that Laravel is built to be a full framework straight out of the box. You can install it and minutes later you can start coding what is needed. This includes APIs or a full-fledged website. Laravel is set up for RAD (Rapid Application Development). You don’t have to do a lot to start working.
Symfony on the other hand, by default, only provides the skeleton to start building APIs with. You don’t get website related components for a front end, etc. For that, you need to put in a little more work before you can start going. For these tests I ran Symfony with just the skeleton. That’s why I changed the response in Laravel to be equal to that of Symfony. I tried to get as close to apples with apples.
Even so, based on my tests (for speed), and opinion, Symfony seems to be the faster framework/system. If you are looking for performance, we have an answer. On the other hand, perhaps performance is not always what you want or need. But this opens a different can of worms for which we need to do some more thinking and testing to see how the two systems compare.