1. Manifesto: The Art of Building Efficient Systems
For many, development ends at the "it works" stage. Their success is measured by the number of closed Jira tickets and successfully deployed features. But for an engineer, this moment is only the beginning. The real work begins where code stops being just text and starts interacting efficiently with the infrastructure.
I am launching the ENGINEERING category because I am convinced that performance is not a "tune-up" performed right before release, nor an attempt to fix "sluggishness" by adding cache at the very last moment. Performance is the foundation of architecture.
Why does this matter?
Development Economics: A system that delivers a response in 200 ms consumes significantly fewer CPU and memory resources. This translates directly into lower cloud infrastructure costs and project longevity.
User Experience: We live in the era of the "instant internet." Every extra 100 ms is a risk that the user will simply close the page. A fast website is a polite website that respects its visitor's time.
Scalability: When a system is designed as an engineering solution, it doesn't "fold" at the first spike in traffic. It is predictable, stable, and easy to diagnose.
This is not magic or luck. It is the result of conscious tool selection, an understanding of what happens "under the hood" (from SQL queries to network latency), and discipline in managing data flows. In this column, I will share how we transform chaotic code into streamlined, high-load systems. We are not talking about "how to do it," but "why it will work reliably for the long run."
2. Redis as a Foundation: More Than Just a Cache
In modern Laravel architecture, the database (MySQL/PostgreSQL) is the "Source of Truth." However, reading from it every time a user requests a page is redundant. Disk I/O operations and complex SQL joins quickly become the primary bottleneck as load increases.
Redis offloads this burden to RAM (In-Memory Data Structure Store). By using it as the CACHE_STORE and SESSION_DRIVER, we create a two-tier system:
Fast Layer (RAM): For frequently requested data (blog pages, complex computation results, sessions).
Reliable Layer (Disk): For long-term storage of data requiring transactional integrity.
Basic Deployment (Ubuntu/Debian)
Installation is a five-minute task, but it is important to understand what we are doing. We are not just setting up a server; we are running a dedicated process that will "carve out" a portion of the server's RAM for our application's needs.
# Update package index and install server
sudo apt update && sudo apt install redis-server
# Install driver for PHP-Redis connectivity
sudo apt install php-redis
After installation, you need to point Laravel to use this layer via the .env file:
# Switch cache and session drivers
CACHE_STORE=redis
SESSION_DRIVER=redis
Data Isolation: Prefix Strategy
Production servers often host multiple applications. If you don't configure naming, the cache of one project will inevitably conflict with another. A prefix is your "digital hygiene."
In config/database.php, we define a strict key structure:
'redis' => [
'options' => [
// Use the project name slug for uniqueness
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_'),
],
],
Why this matters for an engineer:
Cleanliness (Isolation): Your keys like oleant_blog_post_1 will never collide with keys from a third-party application.
Debug-friendly: When you access redis-cli, you see a clear structure rather than a "mush" of random keys. This saves time when searching for "lost" data or clearing the cache for a specific module.
3. Mechanics and Architecture: Implementing responsecache
We selected spatie/laravel-responsecache as the industry standard. It allows us to "short-circuit" a request at the very beginning of the application lifecycle—before Laravel even begins loading heavy services, resolving controllers, or executing SQL queries against the database.
Installation and Initialization
Package Installation:
composer require spatie/laravel-responsecache
Publishing Configuration: For fine-tuning (e.g., excluding pages that shouldn't be cached), we publish the config file:
php artisan vendor:publish --provider="Spatie\ResponseCache\ResponseCacheServiceProvider"
After this, you will have the config/responsecache.php file, where we define the exclusion logic.
Route Integration
In our case, caching is applied globally within the localization group. This is an elegant solution, as it automatically covers all public pages of the site without affecting system or API routes defined outside this group.
By the way, a deep understanding of the request lifecycle is critical for performance. You can read about an underrated method that helps perform heavy tasks after sending the response in our article: "How I Built My Own Laravel Analytics Package (and Almost Didn't Crash Production)"
Route::group(['prefix' => LaravelLocalization::setLocale(),
'middleware' => [
'localizationRedirect',
'localeViewPath',
'cacheResponse' // <- This is where Laravel intercepts the response
]], function () {
// All routes within the group are cached automatically
});
Exception Management
All "rules of the game" are defined in the config/responsecache.php file. In the cache_profile key, you specify a class that extends BaseCacheProfile. This class is where the caching decision logic is concentrated.
Flexibility through Inheritance: The standard CacheAllSuccessfulGetRequests class covers only GET requests and successful responses by default. To change this behavior, you create your own class that extends
BaseCacheProfileand override theshouldCacheRequestandshouldCacheResponsemethods.Specific Exceptions: Within the
shouldCacheRequestmethod, you can define route masks (e.g.,/contactor/admin/*) that must always remain "live." This is critical for forms with CSRF tokens where state must be unique to each user.
Cache Hygiene: php artisan optimize:clear
Caching requires discipline. The cache is the "frozen state" of your application. During deployment or when changing logic (e.g., updating translations), the cache must be kept up to date.
We use php artisan optimize:clear as a mandatory step in our CI/CD pipeline or as the final act of deployment. This command "cleans everything": configs, routes, views, and, of course, invalidates our ResponseCache. This ensures that users always see the current version of your product, not "ghosts" of old code.
4. Monitoring: Evidence-Based Development
Engineering is built on measurability. If you cannot measure a result, you cannot manage it. The redis-cli monitor tool is our "X-ray," allowing us to see exactly how the application communicates with the storage layer in real-time.
How to "Read" Redis
When you run redis-cli monitor in the terminal, you see the stream of commands that Laravel sends to Redis. In a caching architecture, we look for a pattern that confirms efficiency:
Behavior during a "Cache Hit": You will see a quick burst of GET commands for a specific key that matches your project's prefix. This means Laravel didn't reach controller execution or MySQL queries—the data was "caught" directly from RAM. This is the source of our coveted 200 ms response time.
Behavior during a "Cache Miss": If a page takes a long time to load and you see an avalanche of SQL database queries in the monitor (or via the DB general log) or a sequence of SET commands, it means the system is being forced to "warm up" the cache.
Why This Matters to an Engineer
Without this tool, development turns into "guessing games." monitor allows you to:
Verify Architecture: Ensure that the
cacheResponsemiddleware is actually intercepting the request.Identify Bottlenecks: If you see 50+ Redis requests firing just to update a simple page, your caching architecture is likely too granular and needs optimization.
Provide Evidence: When the business asks "why has the site become faster?", you can show more than just a TTFB graph—you show a real-time command stream demonstrating that the database is fully unloaded.
Engineering Discipline: Use redis-cli monitor during testing sessions following major refactors. It is the best way to verify that you haven't accidentally broken cache invalidation and that the application isn't serving stale data from RAM by bypassing the business logic.
Want to check your project's performance in real-time? Use our page load time audit tool to get a detailed TTFB analysis and >identify hidden bottlenecks in your architecture.
5. Architectural Bridge: Filament and Automatic Cache
Invalidation
Using Filament for content management provides incredible development speed, but it raises a question: how do you guarantee content freshness on the frontend? We don't want to manually visit the terminal or admin panel to clear the cache every time a post is published. The engineering approach is event automation.
We implemented an Observer for the Post model. Now, as soon as content is updated in the admin panel, Laravel "sees" this at the model level and clears the cache automatically.
Implementation via Observer:
namespace App\Observers;
use App\Models\Post;
use Spatie\ResponseCache\Facades\ResponseCache;
class PostObserver
{
public function saved(Post $post): void
{
// Automatic cache reset upon post creation or update
ResponseCache::clear();
}
public function deleted(Post $post): void
{
ResponseCache::clear();
}
}
Why this matters:
Consistency: The user always sees fresh content. No "stuck" old headers or fragments of stale text after an edit.
UX for the Editor: The admin doesn't need to worry about the "technical" consequences of clicking the "Save" button. The system handles the entire load of invalidation.
Integrity: We linked database events (Eloquent Events) with the infrastructure layer (Redis). This is precisely what is meant by "systems engineering"—creating a closed loop where changes in one layer are automatically and correctly reflected in another.
Conclusion: The Filament admin panel has become more than just an interface for writing to the database; it is now the "Source of Truth" that autonomously manages the lifecycle of its own representation on the frontend.
6. Summary: Results in Numbers
An engineering approach is always about arguing with facts. Below are the performance benchmark results after implementing Redis and responsecache. We focused on TTFB (Time to First Byte), as it precisely shows how quickly the application "fires" the response, bypassing heavy backend logic.
Performance Benchmark Logs:
{
"homepage": {
"url": "https://oleant.dev",
"http_code": 200,
"dns_lookup_ms": 21.46,
"tcp_connection_ms": 8.26,
"time_to_first_byte_ms": 195.41,
"total_time_ms": 225.94
},
"blog_post": {
"url": "https://oleant.dev/blog/jagd-auf-digitale-chamaleons...",
"http_code": 200,
"dns_lookup_ms": 1.24,
"tcp_connection_ms": 17.23,
"time_to_first_byte_ms": 220.32,
"total_time_ms": 256.69
}
}
Data Analysis:
TTFB ~200 ms: This is a benchmark metric for Laravel applications. We have achieved a state where the server starts delivering data almost instantly after the TCP connection is established.
Minimizing Overhead: The difference between time_to_first_byte and total_time is minimal, indicating an absence of "lag" during content delivery (content is transferred efficiently).
Stability: Even on a heavy article page (with a large number of DOM elements), the response time remained within a user-friendly limit of 250 ms.
Conclusion: Caching via Redis is not a "hack" or a workaround; it is basic architectural hygiene. The project is now ready for load growth without sacrificing user experience. We have laid a foundation that allows the system to scale with the tasks, rather than hitting the capacity limits of the database server.
Top comments (0)