Redis for Cache, Session and FPC
Three independent things point at Redis in Magento, and each needs its own database number.
bin/magento setup:config:set --cache-backend=redis --cache-backend-redis-server=127.0.0.1 --cache-backend-redis-db=0Three separate things in Magento can live in Redis: the default cache (every cache type except the page cache), the page cache (full_page) and sessions. They are configured independently and each should get its own Redis database number, conventionally 0, 1 and 2.
Configuring them
bin/magento setup:config:set writes the values into app/etc/env.php. The option prefixes mirror the three concerns: --cache-backend-redis-*, --page-cache-redis-* and --session-save-redis-*. The command and the file are the same configuration in two forms, so editing app/etc/env.php by hand produces an identical install. Magento 2.4.9 also ships Valkey backends, selected with --cache-backend=valkey and --page-cache=valkey; they did not exist in 2.4.8.
Why separate databases
cache:flush empties the whole storage behind a cache frontend. If the page cache shares a database with sessions, flushing the cache deletes every session. id_prefix keeps two installs apart on one Redis instance, but it does not protect against a flush, because flush does not filter by prefix.
What a restart costs
Restarting Redis without persistence empties it. The cache simply rebuilds, slowly. Sessions do not: every logged-in customer and every admin is signed out. Quote rows survive in the database, so a cart is recoverable on sign-in, but the visitor loses the guest cart they had.
Follow any setup:config:set with bin/magento cache:flush.
Example
<?php
// app/code/Vendor/Ops/Console/Command/CacheBackendCommand.php
declare(strict_types=1);
namespace Vendor\Ops\Console\Command;
use Magento\Framework\App\DeploymentConfig;
use Magento\Framework\Console\Cli;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class CacheBackendCommand extends Command
{
public function __construct(
private readonly DeploymentConfig $deploymentConfig,
?string $name = null
) {
parent::__construct($name);
}
protected function configure(): void
{
$this->setName('vendor:cache:backends');
$this->setDescription('Prints the backend and Redis database of each cache frontend');
parent::configure();
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
foreach (['default', 'page_cache'] as $frontendName) {
$frontend = (array)$this->deploymentConfig->get('cache/frontend/' . $frontendName, []);
$output->writeln(sprintf(
'%s: backend=%s db=%s',
$frontendName,
(string)($frontend['backend'] ?? 'files'),
(string)($frontend['backend_options']['database'] ?? '-')
));
}
$output->writeln(sprintf(
'session: save=%s db=%s',
(string)$this->deploymentConfig->get('session/save', 'files'),
(string)$this->deploymentConfig->get('session/redis/database', '-')
));
return Cli::RETURN_SUCCESS;
}
}
// $ bin/magento vendor:cache:backends
// default: backend=Magento\Framework\Cache\Backend\Redis db=0
// page_cache: backend=Magento\Framework\Cache\Backend\Redis db=1
// session: save=redis db=2When to use it
- Pointing cache, page cache and sessions at Redis on a new production environment.
- Auditing an inherited install to check that nothing shares a Redis database.
- Explaining why every customer was logged out after someone restarted Redis.
More examples
The three commands
Run these on a fresh install or when moving Redis. The defaults already follow the 0/1/2 convention for the database numbers, but state them anyway: the next person reading env.php should not have to know the defaults. --cache-backend-redis-db defaults to 0 and --page-cache-redis-db to 1. Setting the page cache to Redis does not switch Magento from Varnish to the built-in cache; that is a separate config value.
# Default cache: every cache type except full_page.
$ bin/magento setup:config:set --cache-backend=redis \
--cache-backend-redis-server=127.0.0.1 \
--cache-backend-redis-port=6379 \
--cache-backend-redis-db=0 \
--cache-id-prefix=prod_
# Page cache: the full_page cache type, on its own database.
$ bin/magento setup:config:set --page-cache=redis \
--page-cache-redis-server=127.0.0.1 \
--page-cache-redis-db=1 \
--page-cache-id-prefix=prod_
# Sessions: a different subsystem, a third database.
$ bin/magento setup:config:set --session-save=redis \
--session-save-redis-host=127.0.0.1 \
--session-save-redis-port=6379 \
--session-save-redis-db=2 \
--session-save-redis-log-level=3
$ bin/magento cache:flushWhat lands in env.php
This is the longhand of the commands above, and reading it is the fastest way to audit an environment you inherited. Three different database numbers is what you want to see. compress_data is 1 for the default cache and 0 for the page cache because page HTML is large and usually already compressed by the web server. env.php is environment-specific and is not committed, which is why the CLI form exists at all.
<?php
// app/etc/env.php (written by setup:config:set, trimmed)
return [
'cache' => [
'frontend' => [
'default' => [
'backend' => 'Magento\Framework\Cache\Backend\Redis',
'backend_options' => [
'server' => '127.0.0.1',
'port' => '6379',
'database' => '0',
'compress_data' => '1',
],
'id_prefix' => 'prod_',
],
'page_cache' => [
'backend' => 'Magento\Framework\Cache\Backend\Redis',
'backend_options' => [
'server' => '127.0.0.1',
'port' => '6379',
'database' => '1',
'compress_data' => '0',
],
'id_prefix' => 'prod_',
],
],
],
'session' => [
'save' => 'redis',
'redis' => [
'host' => '127.0.0.1',
'port' => '6379',
'database' => '2',
],
],
];Checking the split on the server
Three non-zero database sizes confirm the split is real rather than just written down. If db 0 and db 2 both hold sess_ keys, sessions and the cache are sharing storage and the next cache:flush will sign everyone out. Run this after any infrastructure change, and before trusting a flush in production.
$ redis-cli -n 0 dbsize
(integer) 14823
$ redis-cli -n 1 dbsize
(integer) 2104
$ redis-cli -n 2 dbsize
(integer) 318
$ redis-cli -n 2 --scan --pattern 'sess_*' | head -3
sess_1f0a9c4b2d8e7f6a5b4c3d2e1f0a9b8c
sess_7c6b5a4938271605f4e3d2c1b0a99887
sess_0d1e2f3a4b5c6d7e8f90a1b2c3d4e5f6
Discussion