You add a second Odoo node to your cluster. Within minutes, users start reporting random logouts. Sessions exist on node A but node B has never seen them.
This post maps the community modules that extend or replace Odoo’s native filesystem session store, and the tools available for controlling session lifecycle in production. For readers who skipped Part 1: native sessions are JSON files on disk, stored under {data-dir}/sessions/, one file per session.
When Native Sessions Become a Problem
Odoo’s default FilesystemSessionStore works well for single-server deployments. Multiple workers on the same machine share the same filesystem, so sessions are always accessible regardless of which worker handles a request [8, Odoo 19.0].
The problem arises in two distinct scenarios.
The first is multi-node clusters. When Odoo runs on two or more machines without a shared filesystem, a session file written on node A is invisible to node B. Any request that lands on a different node than the one that created the session finds no session and forces the user back to the login page. An NFS mount can work around this, but it introduces its own failure modes and performance overhead.
The second is GC latency, a problem that only affects Odoo 15.0 and earlier. On those versions, session garbage collection fired on roughly 1 in 100 requests via http.session_gc(): on a server that had accumulated tens of thousands of session files, that directory scan added measurable latency to the unlucky requests that triggered it. Since Odoo 16.0, garbage collection runs in the daily “Base: Auto-vacuum internal data” cron [10], entirely out of the request path, so this latency spike no longer exists on supported versions.
For single-server deployments, native sessions are the right default. The rest of this post is for everyone else.
PostgreSQL-Backed Sessions (session_db)
session_db is an OCA/server-tools module available for Odoo 13.0-19.0 [1][2]. It replaces FilesystemSessionStore with PGSessionStore, which stores sessions in a dedicated http_sessions table in PostgreSQL.
Activation requires one environment variable:
SESSION_DB_URI=postgresql://user:password@host/dbname
No code changes are needed. The module monkey-patches http.root.session_store at startup, transparently replacing the store for the lifetime of the process [1].
The implementation uses a dedicated PostgreSQL connection, separate from Odoo’s ORM connection pool, with automatic retry logic. Each save is an upsert:
INSERT INTO http_sessions(sid, write_date, payload)
VALUES (%(sid)s, now() at time zone 'UTC', %(payload)s)
ON CONFLICT (sid)
DO UPDATE SET payload = %(payload)s,
write_date = now() at time zone 'UTC'
The ON CONFLICT DO UPDATE makes writes idempotent and safe for concurrent workers across multiple nodes [1]. Session data is serialised as JSON, the same format as the filesystem store, so the transition is transparent.
The main reason to choose session_db over session_redis is operational simplicity: if PostgreSQL is already in your stack, you add no new infrastructure. Every Odoo node already has a PostgreSQL connection configured; session_db reuses that dependency rather than introducing a new one.
Redis-Backed Sessions (session_redis)
session_redis is a Camptocamp module from the odoo-cloud-platform repository, available since Odoo 8.0 [3][4][5]. It replaces the session store with RedisSessionStore, routing all session reads and writes through Redis.
The minimum configuration to activate it:
ODOO_SESSION_REDIS=1
ODOO_SESSION_REDIS_HOST=redis-host
ODOO_SESSION_REDIS_PORT=6379
A URL form is also available: ODOO_SESSION_REDIS_URL=redis://.... Optional variables include ODOO_SESSION_REDIS_PASSWORD and ODOO_SESSION_REDIS_PREFIX, which is useful when multiple Odoo instances share a single Redis server.
Session TTLs
One important feature is separate TTL control for authenticated and anonymous sessions [3]:
ODOO_SESSION_REDIS_EXPIRATION=86400 # authenticated, in seconds (1 day)
ODOO_SESSION_REDIS_EXPIRATION_ANONYMOUS=3600 # anonymous, in seconds (1 hour)
The right values depend on your use case. On a standard back-office deployment, anonymous sessions are created by monitoring probes, health checks, and unauthenticated API calls. Keeping them for only an hour or so is sufficient and avoids accumulating thousands of short-lived sessions in Redis. Authenticated users log in once a day and expect their session to survive the working day, so 24 hours is a reasonable default.
On an e-commerce site the trade-off shifts. Anonymous sessions carry the visitor’s cart and wishlist. Expiring them after an hour means a returning visitor who did not log in loses their cart. In that context, setting ODOO_SESSION_REDIS_EXPIRATION_ANONYMOUS to a longer value (24 hours or more) avoids that friction.
Redis Sentinel
Redis Sentinel is supported for high-availability Redis setups. Three additional variables are required when using it: ODOO_SESSION_REDIS_SENTINEL_HOST, ODOO_SESSION_REDIS_SENTINEL_PORT, and ODOO_SESSION_REDIS_SENTINEL_MASTER_NAME. All three must be set together [4].
Redis vs PostgreSQL
Compared to session_db, Redis has lower read latency (in-memory, no SQL round-trip) and handles key expiry natively without a cleanup cron. It is the better fit for very high request volumes where session reads happen on every request, or when a Redis cluster is already part of the infrastructure. If neither of those applies, session_db is simpler to operate.
Session Lifecycle Management
Inactivity-based logout
auth_session_timeout is an OCA/server-auth module available for Odoo 12.0-19.0 [7]. It automatically terminates sessions that have been inactive beyond a configurable threshold. The threshold is set via a system parameter in Odoo’s settings: 2h by default.
This module is independent of the storage backend: it works whether sessions are stored on the filesystem, in PostgreSQL, or in Redis. It is most relevant for security-sensitive deployments: regulated environments, shared workstations, or public-facing Odoo instances where indefinitely open browser sessions are a risk.
Since Odoo 16.0, native Odoo covers part of this ground: the sessions.max_inactivity_seconds system parameter shortens the session expiry (and on recent versions the cookie lifetime as well) without any module. The difference is enforcement timing: the native parameter only takes effect when the daily GC cron reaps the session file, while auth_session_timeout checks inactivity on every request and logs the user out immediately. For strict timeout requirements, the module remains the right tool.
Force-logout API
For cases where inactivity-based expiry is not enough, Trobz contributed auth_session_logout_api to OCA/server-auth [9]. The module exposes a secure API endpoint that allows remote force-logout of a specific user session. As of May 2026 the PR targets Odoo 16.0 and is pending merge — check [9] for current status.
Deterministic GC: past module, now native
The random GC latency problem described in the first section was solved by base_deterministic_session_gc, a module authored by Trobz and contributed to OCA/server-tools for Odoo 12.0-14.0 [6]. It disabled http.session_gc() and replaced it with a scheduled cron action, making cleanup predictable and removing it from the request path entirely. The module required server_wide_modules configuration to load at startup.
Since Odoo 16.0, this design is native: session GC runs in _gc_sessions(), part of the daily “Base: Auto-vacuum internal data” cron, and the per-request http.session_gc() is gone [10]. The inactivity threshold is configurable via the sessions.max_inactivity_seconds system parameter. No module or extra configuration is needed.
The ODOO_SKIP_GC_SESSIONS environment variable still exists in 16.0+, but its meaning is the opposite of what its history suggests: it skips the built-in cron GC entirely [10]. Set it only when session cleanup is handled elsewhere, for example by the TTL mechanism of session_redis, a custom cleanup job on the http_sessions table for session_db, or platform-level tooling.
Which Approach for Your Deployment
Single server, any number of workers: native filesystem sessions are sufficient. Add auth_session_timeout if immediate inactivity-based logout is a security requirement; for a softer expiry, shorten sessions.max_inactivity_seconds (16.0+).
Multi-node cluster: session_db or session_redis is required. The choice depends on existing infrastructure. PostgreSQL already in the stack and no extreme session read throughput: use session_db. Redis already present, or session reads are on the critical path at high volume: use session_redis.
Security-sensitive deployment: add auth_session_timeout regardless of the storage backend. It is orthogonal to where sessions are stored. For deployments that also need immediate remote logout, watch auth_session_logout_api for merge into OCA [9].
Key Takeaways
Odoo’s native filesystem sessions are production-ready for single-server deployments. For multi-node clusters, session_db and session_redis each provide cross-node session sharing with minimal configuration: one environment variable to activate, no code changes. auth_session_timeout is a drop-in addition for inactivity-based logout regardless of storage backend. The random GC latency problem that base_deterministic_session_gc once solved is fixed natively since Odoo 16.0, where session GC runs in the daily auto-vacuum cron instead of the request path.
Back to the series: Part 1 covers the session object, filesystem storage, and the HMAC-based security model in detail. Part 3 is a FAQ answering the session questions we hear most often in production.
Sources
[1] server-tools/18.0/session_db/pg_session_store.py:62-167 (OCA/server-tools)
[2] server-tools/18.0/session_db/README.rst (OCA/server-tools)
[3] session_redis/session.py:20-127 (Camptocamp/odoo-cloud-platform)
[4] session_redis/http.py:24-90 (Camptocamp/odoo-cloud-platform)
[5] session_redis/README.rst (Camptocamp/odoo-cloud-platform)
[6] server-tools/14.0/base_deterministic_session_gc/http.py:15-42 (OCA/server-tools)
[7] server-auth/18.0/auth_session_timeout/__manifest__.py:1-21 (OCA/server-auth)
[8] odoo/http.py:968-1048 (Odoo 19.0 native FilesystemSessionStore)
[9] OCA/server-auth PR #891: auth_session_logout_api (Trobz, targeting 16.0, pending merge)
[10] odoo/addons/base/models/ir_http.py:406-410 (Odoo 19.0, _gc_sessions() autovacuum cron, ODOO_SKIP_GC_SESSIONS)