Laravel has plenty of built-in features and conventions to keep your code clean. But let’s be real: sooner or later, you’ll need to wri...
Laravel has plenty of built-in features and conventions to keep your code clean. But let’s be real: sooner or later, you’ll need to write custom code. The big question is… where do you put it?
If you’ve ever hesitated before creating a new class or stuffing everything inside a controller (because it's easy), you’re not alone. Even devs with 5+ years of Laravel experience struggle with this. Laravel gives you so many places to put custom logic—it’s flexible, but that flexibility can be overwhelming.
So let’s break it down. Here’s where experienced Laravel developers typically put their custom code—and why.
There’s no single right answer. Different types of custom logic belong in different places. Here’s the breakdown:
Where should you put your custom Laravel code? You should create:
Why? You want reusable, self-contained logic that’s easy to test and maintain. Is this definition confusing? That's ok. It's better explained through an example👇
When you’ve got domain-specific logic that doesn’t quite fit into a model, controller, or middleware, a custom class is a great choice. Some devs throw these into app/Library
, app/Services
, or app/Actions
—it’s really up to you. The key is keeping them focused on a single responsibility.
👉 Example: A CurrencyConverter
class that fetches exchange rates and does conversions. Another example is creating a PaymentGateway
class that will include all functions related to payment - initiate()
, capture()
, verify()
etc.
💡 Pro tip: Bind it in a service provider if you want a singleton instance across your app.
Why? You want quick, reusable functions that doesn’t belong to a specific class.
Helpers are great for those little functions you use everywhere—like formatting money, generating slugs, or manipulating arrays. Keep them in a helpers.php
file and load them in composer.json
.
👉 Example: A format_price($value)
function that always returns a formatted currency string.
💡 Use with caution! Overusing global helpers can make dependencies less obvious.
Why? You need to modify or validate requests before they hit your controllers.
Middleware is the best place to handle things like authentication, rate-limiting, logging, and request transformations. It keeps controllers clean and makes sure every request meets certain conditions.
👉 Example: EnsureUserHasRole
middleware that blocks unauthorized access.
💡 Use parameterized middleware if you need to pass arguments dynamically.
Why? Keep your views DRY by extracting repeated logic.
If you find yourself repeating the same logic in Blade templates, you can create custom directives. These make your views cleaner and easier to maintain.
👉 Example: @isMobile(), @isDesktop(), @isTablet()
, which checks the device type and renders sections accordingly.
💡 Bundle related directives into files and then register them in service provider for easy organization.
Why? Keep your app fast by offloading work to background processes.
If something takes longer than a second, it probably belongs in a job. Laravel’s queue system makes it easy to send tasks to the background—things like sending emails, processing videos, or generating long .csv
export files.
👉 Example: SendWelcomeEmail
job that runs asynchronously.
💡 Use database or Redis queues in production. Avoid sync
unless you're debugging.
Why? Automate repetitive work with your own CLI commands.
Need to clean up old records? Send daily reports? Scrape data? A custom Artisan command lets you do all that from the terminal.
👉 Example: php artisan generate:sitemap
to create a fresh sitemap.
💡 Schedule it in app/Console/Kernel.php
if it should run on a regular basis.
Why? Send messages via email, SMS, Slack, WhatsApp, or custom channels.
Laravel makes notifications easy, but sometimes you need a custom notification channel. Maybe you're integrating with Telegram, or maybe you need an in-app notification system.
👉 Example: App\Notifications\NewOrderReceived
or App\Notifications\WhatsAppChannel
.
💡 Use notification queues for better performance.
Laravel’s flexibility gives you a ton of options, but it’s up to you to use them wisely.
The key takeaway? Put code where it makes sense. Keep controllers thin, use dedicated classes for reusable logic, and take advantage of Laravel’s built-in features to stay organized.
Subscribe to our "Article Digest". We'll send you a list of the new articles, every week, month or quarter - your choice.
What do you think about this?
Wondering what our community has been up to?