Session and application-cache storage affects latency, continuity and operations alongside PHP-FPM, OPcache and database tuning. This guide compares files, Redis and Memcached for WordPress and Laravel, including when a simple store is adequate and what a shared service adds. The relevant choice depends on the workload and recovery requirements, whether you use a VPS, dedicated server or colocation.
The configuration examples target Laravel 13.x, PHP 8.3+ and a standalone Redis server, not Redis Cluster. A separate native PHP session example uses the PhpRedis extension. Updating a framework does not automatically replace an existing application’s config files with a new project skeleton; inspect the actual version and configuration.
Sessions vs Cache: What Problem Are You Solving?
Before comparing storage backends, it helps to separate two concepts that are often mixed in the same sentence: sessions and cache.
- Server-backed sessions: Data associated with a browser/user session, such as form progress or state for an authenticated web flow. A cookie typically identifies the server-side record; lifetime and invalidation depend on the application. Other models, such as Laravel’s cookie driver, also exist.
- Regenerable cache: Reusable query/API results or fragments with a reliable source of truth. A cache miss should be handled, but a backend connection failure does not automatically behave as a miss or trigger a safe fallback. Session state, locks, rate-limit counters and queue jobs require separate loss policies.
WordPress authentication cookies and tokens are distinct from native PHP session files. WooCommerce’s default session handler uses its own cookie and woocommerce_sessions database table, with object-cache access where available. Changing PHP’s session handler or adding object cache does not automatically move that table into Redis. Laravel separately configures session, application-cache and queue drivers; config:cache and route:cache compile local framework files and are not selected by a Redis application-cache setting.
Once you see sessions and cache as separate concerns, the trade offs between files, Redis, and Memcached become much clearer.
Option 1: File Based Sessions and Cache
Native PHP defaults to the files session handler, but only requests that start a PHP session need one; this is not the WordPress or Laravel default by implication. Laravel 13’s new-project session and cache defaults are database. File storage remains an option when the application has a suitable writable directory, restricted access and a cleanup/lifecycle policy.
When File Storage Is Good Enough
File storage can be a suitable choice in these situations:
- Single server, modest traffic: A corporate site, a small blog, or an internal dashboard whose session workload fits the server’s storage capacity.
- Shared hosting without a Redis or Memcached option: If the plan does not provide either backend or allow you to install one, file based sessions may be a practical choice when disk performance is adequate.
- Development: A simple local store can help early testing. Staging should represent production drivers, topology and failure behavior.
If measurements show that file-session latency and concurrency fit the workload, moving the backend may not address the main bottleneck. Review PHP-FPM settings for WordPress and WooCommerce and OPcache alongside storage measurements; an NVMe label is not a performance result. Related guides are also available on the DCHost blog.
Common Bottlenecks and Pitfalls With Files
File based sessions have three main issues as your site grows:
- Locking overhead: PHP locks the session file while a request is working with it. Long running requests can therefore delay other requests that need that same session file.
- Slow or overloaded disks: On busy shared hosting or on HDD based servers, repeated disk access for thousands of session files can create noticeable latency.
- Multi server setups: If session files must be shared across web servers, NFS or another shared file system is one option. That shared storage can introduce a failure point and an I/O bottleneck.
The lock description applies to native PHP’s files handler. Calling session_write_close() after all session updates can shorten its lock duration; later changes are not automatically persisted. Laravel allows requests for the same session to run concurrently by default. If concurrent writes can lose updates, evaluate Laravel’s supported session-blocking mechanism separately. Changing the storage backend does not itself settle the concurrency model.
File caching can also become an I/O bottleneck under load. Compare its measured read and write latency with an in memory backend rather than assuming every file operation reaches physical disk or that a remote cache will always be faster.
Option 2: Redis for Sessions and Cache
Redis is an in memory key value database that can persist data to disk and supports rich data structures.
Why Redis Fits PHP Workloads So Well
- In-memory access: Active data can be read without file-storage latency; the network, command and load still affect end-to-end results.
- Operations and structures: Counters, hashes, lists and sets can support application features. An atomic command does not automatically make a multi-step application workflow atomic.
- RDB/AOF: Configurable recovery can preserve data across restarts, with a loss window depending on settings. Persistence is neither a backup policy nor continuous-availability guarantee.
- Shared access: App servers can use a common backend when client support, permissions and connectivity are configured. They then depend on that backend’s availability and consistency.
For example, a PHP application on a VPS or dedicated server could use Redis for sessions, cache, queues, and real time counters, with storage policies chosen for each workload.
Redis for WordPress: Object Cache, Transients, and Sessions
For WordPress, distinguish these potential Redis integrations:
- Persistent object cache: With a persistent object-cache integration, WordPress can store reusable query results and computed values in Redis, potentially reducing MySQL load. We walk through the full setup in our guide on WordPress object cache with Redis or Memcached.
- Transients backend: Verify how the site’s transients use the chosen persistent-cache integration and size that backend for the workload; moving data out of database storage does not remove capacity limits.
- Plugin sessions: A shared session backend is a separate integration from object caching. Verify that each plugin supports the intended session backend before planning a multi server deployment.
For a high traffic WooCommerce store on a VPS or dedicated server, evaluate Redis object caching separately from session storage. An object-cache integration does not automatically replace the store’s session handler. Choose the session backend only after checking compatibility, then measure performance alongside PHP-FPM and database tuning.
Redis for Laravel: Sessions, Cache, and Queues
Laravel 13 supports the PhpRedis extension and the PHP-only predis/predis Composer client; use REDIS_CLIENT=predis when that supported client is installed. Predis does not itself provide native PHP’s session.save_handler=redis handler. The example below uses PhpRedis, an existing local standalone Redis service and a configured app account. Replace the password placeholder with the account’s secret, keep it out of version control, and use suitable application/environment-specific storage and prefixes.
The .env and database-config examples are a pair. They do not migrate existing sessions or pending jobs:
SESSION_DRIVER=redis
SESSION_CONNECTION=session
SESSION_STORE=redis
CACHE_STORE=redis
REDIS_CACHE_CONNECTION=cache
REDIS_CACHE_LOCK_CONNECTION=default
QUEUE_CONNECTION=redis
REDIS_QUEUE_CONNECTION=queue
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_USERNAME=app
REDIS_PASSWORD=REPLACE_WITH_YOUR_REDIS_PASSWORD
REDIS_PORT=6379
REDIS_PREFIX=dchost_app_
REDIS_DB=0
REDIS_CACHE_DB=1
REDIS_SESSION_DB=2
REDIS_QUEUE_DB=3
CACHE_STORE=redis selects stores.redis in config/cache.php; REDIS_CACHE_CONNECTION=cache chooses its Redis connection. SESSION_CONNECTION=session and REDIS_QUEUE_CONNECTION=queue select the session and queue connections. The custom REDIS_SESSION_DB/REDIS_QUEUE_DB variables have an effect only because the following configuration reads them.
This is the Redis section of config/database.php, not the whole file. Merge it with the application’s existing configuration, preserving required TLS, URL and retry options. If an existing REDIS_URL or customization overrides the same connection fields, verify the effective target:
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'prefix' => env('REDIS_PREFIX', 'dchost_app_'),
],
'default' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => (int) env('REDIS_PORT', 6379),
'database' => (int) env('REDIS_DB', 0),
],
'cache' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => (int) env('REDIS_PORT', 6379),
'database' => (int) env('REDIS_CACHE_DB', 1),
],
'session' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => (int) env('REDIS_PORT', 6379),
'database' => (int) env('REDIS_SESSION_DB', 2),
],
'queue' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => (int) env('REDIS_PORT', 6379),
'database' => (int) env('REDIS_QUEUE_DB', 3),
],
],
The Laravel 13 skeleton’s cache, session and queue config files must read these selectors. An older/custom application might still read CACHE_DRIVER; the application’s config decides the name. Here cache uses DB 1, sessions DB 2, queues DB 3 and default DB 0. The cache-lock connection is explicitly default. These are logical namespaces on one server, not separate memory or eviction budgets; Redis Cluster supports only DB 0.
Typical Laravel patterns with Redis include:
- Sessions: A shared backend for session-using web flows, with explicit lifetime and concurrent-update behavior.
- Application cache: Regenerable results with keys, TTLs and invalidation; this does not place compiled config/route files in Redis.
- Redis queues: A supported Laravel queue backend, with job recovery and loss requirements distinct from cache.
Our Laravel production tuning guide covers the surrounding PHP-FPM, OPcache and worker architecture. Check its assumptions against your deployed versions and workload.
Redis Drawbacks and Gotchas
Redis is powerful, but it is not magic. You should be aware of a few trade offs:
- Needs RAM: Size memory for the active dataset and operational overhead. Insufficient RAM can cause severe performance or availability problems; swapping is not an inevitable outcome on every system.
- Persistence settings determine crash recovery: Persistence does not guarantee that every acknowledged write survives a crash. For example, AOF with an every-second fsync policy can lose recent writes. This is usually acceptable for cache, but more sensitive for sessions.
- Eviction policy matters: If you use the same Redis instance for sessions and cache, a bad
maxmemoryand eviction configuration can cause user sessions to be evicted under pressure. We go deeper into TTL and eviction strategy in our Redis vs Memcached tuning playbook for WordPress and WooCommerce.
maxmemory is not a cap on the entire Redis process’s RSS. Replication/persistence buffers and other overhead need headroom within the VPS budget. TTL expiration and eviction are different: noeviction prevents capacity eviction but does not prevent expiry, and it can cause memory-growing writes to fail. The application must handle that failure.
Consider separate Redis instances when cache, sessions and queues need different memory/eviction policies. Logical databases on one instance only separate key namespaces and DB-scoped operations: they still share the process, RAM, CPU, eviction behavior, failure domain and RDB/AOF files. Prefixes and DB numbers are not authorization boundaries. Separate instances on the same VPS still share host resources.
Option 3: Memcached for Sessions and Cache
Memcached is a key/value cache service. Standard use keeps data in memory and requires the application to tolerate misses or lost cached values. Supported session drivers exist, but the service’s availability and loss behavior must fit the session workload.
Where Memcached Still Makes Sense
Memcached is a strong candidate when:
- Regenerable key/value cache: The required operations and TTL behavior fit the selected integration.
- Operational fit: The team can size memory, secure access and handle failures with its supported client.
- Distribution: A suitable client or proxy can distribute keys across servers; distribution alone does not provide replication or session durability.
For simple get and set workloads, compare performance under your own traffic patterns as well as ecosystem support and features.
Memcached Limitations You Need to Know
Memcached is intentionally limited, which matters for your design:
- Recovery: Standard cache use must tolerate data loss. Optional warm restart can preserve cache across compatible clean restarts but is not crash-safe. Extstore can place values on flash while retaining keys in RAM; it is not a general durability guarantee.
- Replication and availability: Design these with the supported client/proxy and infrastructure; adding servers does not automatically replicate every session.
- Item limits: Check the configured maximum item size and serialization overhead. Oversized cached values or sessions can fail to store; do not assume an arbitrary limit applies to every build.
For session data, choose Memcached only when its possible loss and recovery behavior are acceptable and the integration is supported. For regenerable WordPress or Laravel cache, compare it with Redis using representative workload measurements and the team’s operational requirements.
Files vs Redis vs Memcached: Comparison by Criteria
Here is a high level comparison of the three options across key dimensions.
| Criterion | Files | Redis | Memcached |
|---|---|---|---|
| Setup | Appropriate directory, permissions and lifecycle management | Service and compatible client; Laravel supports PhpRedis or Predis, native Redis sessions require the PhpRedis handler | Service and supported integration; Laravel/native examples use the PHP Memcached extension |
| Performance | Depends on storage, locking model and workload | Depends on operations, memory, network and load | Depends on client, memory, network and load |
| Recovery | Depends on filesystem durability and cleanup | Configured RDB/AOF with an evaluated loss window | Cache loss must be tolerated; optional clean warm restart is not crash safety |
| Multiple servers | Needs a deliberate sharing/stickiness and node-failure plan | Shared network backend with client/topology and failure requirements | Supported shared access/distribution with explicit loss handling |
| Potential fit | Adequate measured single-node session/cache workloads | Supported session, cache, Redis queue and counter integrations | Regenerable cache and session uses that accept its loss behavior |
Choosing Storage for Common WordPress Scenarios
If you run a classic blog or a brochure site with a page builder, low to medium traffic, and a single hosting account, you do not need to rush into Redis.
- If a plugin uses PHP sessions, file storage may be sufficient for this small, single-server setup; assess sessions separately from WordPress object caching.
- Use a good page cache plugin or LiteSpeed Cache if your plan supports it. Our hosting performance guide for Elementor, Divi and other builders explains how to size CPU and RAM correctly.
- If session file I/O is a measured bottleneck, assess storage latency and contention rather than relying on the SSD or NVMe label alone.
Choose the next optimization from measured PHP, database, image, network and storage costs. A small site does not need an extra cache service solely because another site uses one.
2. Growing WooCommerce Store on a VPS
As traffic and campaign peaks grow, measure session-storage latency and database load before choosing a cache backend. Consider these layers separately:
- Session storage: Identify the session handler used by the store and its plugins before selecting a backend. Do not assume that changing PHP’s session handler or installing an object cache moves every checkout and account session into Redis.
- Persistent object cache in Redis: Reuse cacheable objects and query results to reduce repeated database work. Combine this with the tuning ideas in our WordPress server tuning guide.
- Page cache at web server or CDN level: This reduces PHP work for cacheable public responses. Bypass cart, checkout, account, session-specific, and other personalised or dynamic API responses, even for anonymous visitors; our guide on Nginx microcaching for PHP shows what is possible even on a single VPS.
Compare cache tuning with hardware upgrades against the bottleneck you measured. Evaluate concurrent-user capacity and TTFB under representative store traffic before attributing an improvement to Redis or NVMe storage.
3. WordPress Behind a Load Balancer or Reverse Proxy
If a plugin uses file based PHP sessions, running it across multiple web servers raises a session-sharing problem. Keeping sessions in files requires a strategy such as sticky sessions or shared storage, with corresponding availability and operational trade-offs.
A shared-storage design can include:
- For components using native PHP sessions, evaluate a compatible shared handler; WooCommerce’s default table-backed handler remains a separate concern.
- A persistent object cache can use a supported Redis integration. On standalone Redis, another DB number provides a namespace, not resource/eviction isolation. Redis Cluster supports only DB 0; use a compatible topology and separate instances when policies must differ.
- Plan proxy and node-failure behavior; our Nginx reverse proxy and load balancer guide provides a complementary architecture example.
Sentinel with replicas is one possible Redis failover design, but requires compatible clients and independently placed monitoring components. Asynchronous replication can lose acknowledged writes during failure; test recovery and data loss rather than treating replicas as a guarantee. Our high availability Redis guide discusses that separate topic.
Choosing Storage for Common Laravel Scenarios
1. Internal Tools and Admin Panels
For small internal applications with limited concurrency, Laravel sessions and cache on files or database can be perfectly acceptable:
- Evaluate file or database session/cache drivers against the workload; Laravel 13 uses
CACHE_STOREto select the application cache store. - A single-node design can simplify session access if its capacity and recovery limits are acceptable; it is not a universal deployment requirement.
- Measure PHP-FPM, OPcache and database behavior alongside storage.
For the file option use CACHE_STORE=file; database stores need their configured tables. Both can be valid production choices when the workload fits. Staging should represent production drivers and failure modes.
Consider Redis later if measurements identify session or cache storage as a bottleneck. Plan the migration, including service and client setup, existing session continuity, and cache repopulation, rather than treating it as only a configuration change.
2. Public APIs and Mobile Backends
Public APIs often authenticate with JWTs or access tokens rather than browser sessions, reducing reliance on server side session storage. However, they can hit the cache very heavily for rate limiting, application values, feature flags, and aggregated responses.
This refers to application data, not Laravel’s compiled config/route cache files. Token authentication can also have server-side checks; it is not automatically stateless in every application.
Where the supported operations and measured workload fit, Redis can serve these roles:
- Application-cache lookups with measured latency and a failure policy
- Rate-limit counters through a supported framework store, with concurrency behavior verified
- Admin web sessions where a shared backend and its recovery policy meet the application’s needs
Memcached is also an option for cache lookups. Choose between it and Redis based on the operations and framework integrations the API needs, rather than assuming one always performs better.
3. High Traffic SaaS With Background Jobs
For a busy Laravel SaaS platform with queues, broadcasting, and multiple web servers, consider a design that keeps shared state outside individual app servers:
- Supported shared sessions with an explicit idle lifetime, cookie settings and concurrent-update plan
- Regenerable application cache with TTL/invalidation and its own loss policy; separate instances when eviction/resource policies must differ
- Redis queues monitored by Horizon when that integration is used. Horizon is not a generic monitor for other queue backends and Laravel 13 documentation excludes Redis Cluster.
- App nodes with matching keys/configuration and shared state dependencies whose failover and recovery have been tested
Alongside the earlier connection configuration, this production example uses a hypothetical 120-minute idle session lifetime and HTTPS cookies. HTTPS/proxy handling must be correct. Merely naming a file .env.production or putting APP_ENV=production inside it does not select it: Laravel checks externally supplied APP_ENV or the CLI –env argument before loading that file, otherwise it uses .env.
APP_ENV=production
APP_DEBUG=false
SESSION_DRIVER=redis
SESSION_CONNECTION=session
SESSION_STORE=redis
SESSION_LIFETIME=120
SESSION_SECURE_COOKIE=true
SESSION_HTTP_ONLY=true
SESSION_SAME_SITE=lax
CACHE_STORE=redis
REDIS_CACHE_CONNECTION=cache
REDIS_CACHE_LOCK_CONNECTION=default
QUEUE_CONNECTION=redis
REDIS_QUEUE_CONNECTION=queue
Rebuild the verified configuration with php artisan config:cache as part of deployment; changing .env does not update an existing config cache. Plan how long-running workers/Horizon receive the new configuration. A store migration does not automatically convert old session serialization or pending jobs; retain compatible APP_KEY/cookie settings across nodes, plan continuity or controlled reauthentication, and validate rollback against newly written data.
This is effectively the pattern we describe in our Laravel on VPS deployment guide. One design option is to start with Redis on the application server and later move it to a separate node. Plan connection-setting changes, network access controls, and data migration before making that move.
Quick Decision Checklist
If you are uncertain, this simple checklist often points in the right direction:
- Single node: Files/database may fit measured session/cache needs; a WordPress site may not use native PHP sessions at all.
- Dynamic store or Laravel app: Identify the actual session owner, assess object/application-cache reuse and monitor resource/connection errors.
- Multiple nodes: Use a compatible shared-state design and test concurrent requests, node failure and deployment continuity.
- Critical state: Select durability, isolation and recovery from acceptable loss and downtime; Redis, backups or a second server do not automatically satisfy them.
Practical Configuration Tips on a VPS or Dedicated Server
1. PHP, FPM, and OPcache Still Matter
Switching to Redis will not fix a misconfigured PHP environment. Before or alongside changing session and cache storage, make sure:
- Use a PHP version supported by the application and dependencies; the Laravel 13 example requires PHP 8.3+. PHP 8.x upgrade checklist for WordPress and Laravel provides broader upgrade checks.
- Fit PHP-FPM concurrency to one shared memory budget; PHP-FPM settings guide is a related guide.
- Confirm OPcache behavior and workload needs. Check that the expected Redis/Memcached client is installed in the actual PHP-FPM runtime, not just a different CLI binary.
Evaluate these layers together. A backend change can help a measured storage bottleneck, but it does not replace correct application, PHP or database behavior.
2. Baseline Redis Settings for Sessions and Cache
For the standalone Redis example, record the existing settings and review each role’s budget before making changes:
- Isolation: Logical DBs and prefixes do not prevent cache pressure from affecting sessions/queues in the same instance. Separate instances can use different policies, while still sharing the VPS’s resources.
- Memory: Budget Redis with PHP, the database, OS and persistence/replication overhead. There is no universal 50–70% allocation rule; maxmemory is not the full process RSS limit.
- Eviction: An allkeys policy such as
allkeys-lrucan suit disposable cache.noevictionrejects memory-growing writes instead of evicting for capacity; TTL expiry and application errors still require handling. - Persistence: Evaluate RDB/AOF loss windows, backups and restoration against session/job requirements, not just whether snapshots are enabled.
- Access: Restrict Redis to intended trusted clients, configure ACL/authentication, and verify required TLS for network links. Localhost or a private network alone does not settle all authorization needs.
php artisan cache:clear redis flushes the selected Redis cache store’s DB, without limiting the deletion to its key prefix. In the earlier correctly mapped example, that is DB 1, not session DB 2 or queue DB 3. Other keys sharing DB 1 would be affected. Do not use production cache clearing as a diagnostic experiment.
Monitor Redis memory usage, key counts, and latency. If you already use tools like Prometheus and Grafana for your VPS, add Redis exporters and alerts alongside CPU and disk metrics.
For a separate native PHP session integration, the PhpRedis handler must be installed in the target SAPI. The following authenticated local example is not a Laravel session configuration and does not replace WooCommerce’s handler. Replace the account/password placeholders, URL-encoding the secret for the query string, and verify access before adoption:
session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379?database=2&prefix=PHPSESSID_&auth[]=app&auth[]=REPLACE_WITH_URL_ENCODED_PASSWORD&timeout=2.5"
redis.session.locking_enabled = 1
PhpRedis session locking defaults off; this example enables it. Test lock lifetime, wait/retry settings and request timeouts against the longest relevant request. Its documented locking support is for a single-master setup, not a general RedisArray/Cluster guarantee. Native PHP session.gc_maxlifetime uses seconds; Laravel SESSION_LIFETIME uses minutes. A switch does not transfer existing sessions automatically.
3. Memcached Sizing and Key Strategy
If you choose Memcached for cache, keep these points in mind:
- Allocate memory within the same host budget used for PHP-FPM, the database and OS.
- Use application/environment-specific keys for collision avoidance, without treating a prefix as an authorization or eviction boundary.
- Handle cache misses, evictions and connection errors separately; a missing value and an unavailable service need not have the same result.
- Restrict access to trusted clients and supported transports; do not expose Memcached directly to untrusted networks.
A supported persistent object-cache integration can serve WordPress transients outside the database. Their expiry is a maximum lifetime, not a guaranteed minimum: values may disappear early and must be regenerable. Measure the actual hit rate and saved database work.
4. Monitoring and Troubleshooting
New storage layers can introduce new failure modes. Some practical tips:
- Log and alert on Redis or Memcached connection failures from PHP.
- Watch for spikes in PHP session start times or Laravel response times after enabling a new driver.
- Monitor VPS resources; our guide on monitoring VPS resource usage with htop, iotop, Netdata and Prometheus is a good starting point.
If performance worsens, check the effective driver and endpoint, client timeouts, network access, cache misses/evictions and host pressure together. Exercise login/logout, CSRF/forms, guest and signed-in carts, concurrent session writes, scoped cache clearing and planned restart/recovery in staging; compare the same representative load before and after. Keep diagnostics access-controlled.
Planning Storage on DCHost Infrastructure
A possible progression, when measurements and operational needs justify it, is:
- Use a hosting plan that supports the application’s actual session/cache driver and appropriate storage lifecycle.
- Choose VPS control when required for PHP configuration or a dedicated cache service, verifying available resources and permissions.
- Separate roles when budgets or independent policies justify it; a separate Redis server still needs a tested availability/recovery design.
- Evaluate dedicated hardware or colocation against costs and management responsibilities, with database, cache and application roles deliberately planned.
Choose from traffic measurements, loss tolerance and operational support. Files can be adequate; Redis supports several useful state/cache integrations; Memcached is an option when its supported features and loss behavior fit. Compare the complete design rather than assigning a universal winner.
Record the current configuration and rollback path, map each session/cache/queue owner to its real connection, and test one change under representative load. Measure response and query times, cache hit/miss, connection failures and resource demand. Preserve login, cart and job continuity during migration; use the linked WordPress and Laravel guides for their separate configuration scopes.





