A Week in a Different World: A Laravel Dev's Thoughts on Symfony
Hey everyone, Jamie here.
As developers, we tend to build our “homes” in certain frameworks and ecosystems. For me, and for much of this blog, that home has been Laravel. I appreciate its elegant syntax, its “batteries-included” philosophy, and the sheer speed at which you can build robust, modern applications. It's a fantastic tool that I know and love.
Recently, however, I had the opportunity to dive deep into a project built purely on Symfony. It wasn't just about using a few Symfony components under the hood (which Laravel does extensively), but about working within the complete Symfony framework, with its own conventions, structure, and mindset.
It was a fascinating experience that felt like visiting a well-designed, but very different, city. It made me appreciate not only what Symfony does so well but also gave me a fresh perspective on why Laravel works the way it does.
The Initial Shock: “Where's the Magic?”
My first few hours with the Symfony project were a lesson in humility. As a Laravel developer, you get used to a certain amount of “magic” and convention. Things just work.
- Eloquent vs. Doctrine: I found myself missing the simplicity of Eloquent. In Symfony, the default ORM is Doctrine. It's incredibly powerful and robust, but it's also more verbose. Defining entities, repositories, and mappings felt more deliberate and required more boilerplate than simply creating a new Laravel model.
- Configuration Over Convention: Laravel famously favors convention over configuration. In Symfony, the opposite is often true. I spent a good amount of time in YAML files (
services.yaml
), explicitly defining services and their dependencies. My first reaction was, “Why do I have to wire all this up myself?” - No Facades, Just Services: There are no global helpers like
auth()
orcache()
. There are no facades providing a simple, static-like interface to underlying services. Everything is a service, and if you want to use it, you must explicitly inject it into your class's constructor.
It felt like the framework was forcing me to be incredibly explicit about every single thing I was doing.
The Slow Appreciation: The Power of Explicitness
After the initial friction, something started to click. The very things that felt like hurdles at first began to reveal their purpose and power.
- Dependency Injection is a First-Class Citizen: Because you have to inject every dependency, your code becomes incredibly clear. You can look at any class's constructor and know exactly what its dependencies are. This makes the code highly predictable, decoupled, and exceptionally easy to test. You're not guessing where a service comes from; it's right there.
- Unmatched Flexibility: Symfony feels less like a framework you build inside of, and more like a set of high-quality components you build your application with. You have complete control. You can swap out almost any part of the system with your own implementation. This level of flexibility is fantastic for large, complex, or long-lived enterprise applications where requirements are unique and evolving.
- Stability and Predictability: The lack of “magic” means there are fewer surprises. The call stack is often easier to trace. You can follow the path from configuration to instantiation to execution without the framework doing things behind a curtain. This can be a huge advantage when debugging complex issues.
What I Missed From Laravel: The Joy of Convention
As I grew to appreciate Symfony's architecture, I also found myself missing the sheer developer experience and rapid development cycle that Laravel provides.
- Eloquent's Elegance: For all of Doctrine's power, I missed the beauty of defining a
hasMany
relationship in a single line and chaining query builder methods with such ease. For 90% of standard CRUD and API tasks, Eloquent's speed and readability are hard to beat. - The “Batteries-Included” Ecosystem: Laravel's first-party packages like Sanctum, Telescope, and Sail create a seamless, cohesive development experience. Setting up API authentication with Sanctum, for example, is a beautifully simple process. In Symfony, you're more likely to be assembling and configuring different bundles to achieve the same result.
- Artisan and the
make
Commands: I missed the convenience ofphp artisan make:model -mcr
. Laravel's command-line tools are tailored for rapid scaffolding and reducing boilerplate, which keeps you in the creative flow.
The Right Tool for the Job
My time with Symfony didn't make me think Laravel is “better” or vice-versa. It solidified my belief that they are two different tools with different philosophies, both built on the same excellent foundation of modern PHP.
- Symfony feels like a meticulously organized workshop full of high-end, individual power tools. It gives you the power and flexibility to build anything, but it expects you to be a skilled craftsperson who knows how to assemble them. It shines for complex, bespoke, long-term projects.
- Laravel feels like a state-of-the-art, all-in-one workstation. It has pre-configured tools, sensible defaults, and clever jigs that let you build common things incredibly quickly and elegantly. It shines for rapid application development, APIs, and a huge range of web applications.
Ultimately, working with Symfony made me a better PHP developer. It forced me to engage with concepts like the service container and dependency injection on a much deeper level. And when I returned to a Laravel project, I had a newfound appreciation for the thoughtful conventions and the “magic” that lets me focus on building features so quickly.
What are your experiences moving between the two frameworks? I'd love to hear your thoughts in the comments.
Cheers,
Jamie C