Every few years the web development world reaches a consensus that some technology is dead. PHP has been declared dead at least four times. It powers 77% of the web's server-side code.
Frameworks have gone through their own cycle. You're not a serious developer if you're not using Laravel. Or Symfony. Or whatever has the most GitHub stars this month.
We've built projects in Laravel, Slim, and CodeIgniter. We've also built production applications in completely framework-free PHP. Here's what we've actually learned.
What a Framework Actually Gives You
To have an honest conversation, we need to be clear about what you're getting:
- Routing — a clean way to map URLs to code
- ORM — an abstraction over SQL queries
- Templating — a way to separate logic from presentation
- Authentication scaffolding — pre-built login systems
- Artisan / CLI tools — code generation, migrations, queue workers
- Conventions — an agreed structure so teams can navigate each other's code
- Ecosystem — packages, tutorials, Stack Overflow answers
That's genuinely valuable. A senior developer with Laravel experience can be productive from day one on a Laravel project. The conventions pay for themselves in large teams.
What a Framework Actually Costs You
- A learning curve — Laravel has hundreds of thousands of words of documentation. You don't learn PHP, you learn Laravel.
- Abstraction debt — when something goes wrong in Eloquent's SQL generation, you need to understand both PHP and the framework internals to debug it
- Dependency sprawl —
composer installpulling in 70+ packages for a CRUD app - Performance overhead — Laravel's bootstrapping alone adds 20–80ms to every request before your code even runs
- Framework lock-in — your application logic is coupled to framework conventions. Migrating away is painful.
- Security surface — every dependency is a potential vulnerability
None of these are dealbreakers. They're trade-offs. The question is whether they're the right trade-offs for your project.
When We Reach For a Framework
**Large teams building complex applications.** Conventions matter when five developers are collaborating. Laravel's structure means everyone knows where the model lives, what the controller does, and where the routes are defined. That consistency is worth the overhead. **Applications with complex relational data.** Eloquent ORM and Laravel's relationship system make complex queries readable and maintainable. Raw PDO becomes messy at scale. **Projects with authentication, queues, and scheduled tasks.** Laravel's ecosystem handles these elegantly. Rolling your own job queue in plain PHP is not a good use of time. **When a junior team needs to maintain it.** Laravel is well-documented, widely understood, and hiring for it is straightforward.When We Don't
**Performance-critical small applications.** A brochure site with a CMS that serves 5,000 pages per day doesn't need Eloquent. It needs fast file reads and clean output. **Security-sensitive proprietary tools.** Every dependency in your `composer.json` is code you didn't write and don't fully control. For our security layer, we wanted to know exactly what every line did. Vanilla PHP gave us that. **Long-lived codebases with no team change.** Framework major versions break things. Laravel 5 to 6 to 7 to 8 to 9 to 10 — each transition requires migration work. A vanilla PHP application from 2015 still runs on PHP 8.3 with minor adjustments. **When the framework's conventions fight your domain.** Some business problems have shapes that don't fit MVC neatly. Forcing them into the pattern creates friction and awkward abstractions.What Vanilla PHP Looks Like in 2025
Modern PHP is not the PHP of 2008. PHP 8.3 has:
- Named arguments and union types
- Fibers (lightweight coroutines)
- Match expressions
- Nullsafe operator (
?->) - Enums
- First-class callable syntax
- JIT compilation
Writing clean, modern PHP without a framework looks like this:
function lw_get_posts(int $limit = 0, string $category = ''): array {
$posts = [];
foreach (glob(CONTENT_DIR . '/*.md') as $file) {
$post = lw_parse_content(file_get_contents($file), basename($file, '.md'));
if (!$post || ($post['status'] ?? 'live') === 'draft') continue;
if ($category && strtolower($post['category'] ?? '') !== strtolower($category)) continue;
$posts[] = $post;
}
usort($posts, fn($a, $b) => strtotime($b['date']) - strtotime($a['date']));
return $limit > 0 ? array_slice($posts, 0, $limit) : $posts;
}
That's readable, typed, and dependency-free. A junior developer can follow it. A senior developer can extend it. It will still run in a decade.
The Honest Answer
Use a framework when the project's complexity justifies it. Don't use one when it doesn't.
The worst codebases we've inherited were not written in plain PHP. They were Laravel applications where someone used the framework's scaffolding to build something simple, added 40 packages for features they could have written in 20 lines, and left the next developer with a dependency graph that takes 45 minutes to understand.
Frameworks are tools. Pick the right tool for the job, not the one with the best conference talks.