Hey!
Summary
This RFC proposes a two-step improvement to the MODX Revolution session subsystem:
- Refactor session handling behind a dedicated abstraction without changing runtime behavior.
- Introduce Deferred Session Creation (Lazy Session mode) so anonymous requests do not create sessions unless one is actually needed.
The primary goal is to reduce unnecessary session creation and slow growth of the modSession table on high-traffic sites while preserving full backward compatibility.
Motivation
A long-standing issue in MODX is that sessions are created too early and too often, especially for anonymous visitors. On busy sites this can cause the session table to grow very large, increasing database load and cleanup cost.
A maintainer-friendly solution should:
- preserve existing behavior initially,
- isolate session lifecycle logic into one place,
- make future storage improvements possible,
- avoid breaking extras or authentication flows,
- allow deferred session creation only after the abstraction is in place.
Problem Statement
Current session logic is tightly coupled to the core bootstrap and authentication flow. In practice this means:
- sessions are started very early,
- anonymous traffic can create a large number of session rows,
- cleanup depends on garbage collection and/or external maintenance,
- the session lifecycle is not centralized behind a clear service boundary,
- future storage changes are harder than they should be.
The result is a maintenance and scalability problem, not just an implementation detail.
Goals
- Introduce a single session lifecycle service in the core.
- Remove direct
session_start(),session_destroy(), and related calls from scattered locations. - Preserve current behavior in the first PR.
- Add a configurable mode for deferred session creation in a second PR.
- Keep all existing authentication and extras behavior working by default.
- Make it possible to add future session storage providers later.
Non-goals
- No rewrite of authentication.
- No forced migration away from database-backed sessions.
- No Redis-only solution.
- No breaking API changes.
- No changes to template rendering, routing, or resource model unless strictly required by the refactor.
Proposed Plan
This work is intentionally split into two implementation PRs, with an initial research step.
PRD-0: Research and architecture mapping
Before implementation, document the current lifecycle:
- where session initialization happens,
- where sessions are written, destroyed, or regenerated,
- how
modUser,modRequest,modX, and manager-side code interact with sessions, - where
$_SESSIONis accessed directly, - what risks exist for extras compatibility,
- whether deferred creation is technically feasible without breaking behavior.
PRD-1: Session abstraction refactor
Introduce a session manager abstraction and move core session operations behind it. This PR must not change behavior.
PRD-2: Deferred Session Creation
Add a new session mode that avoids creating sessions for anonymous requests until a session is actually needed.
Proposed Architecture
Step 1: SessionManager
Create a dedicated service responsible for:
- starting sessions,
- checking whether a session is started,
- regenerating session IDs,
- destroying sessions,
- providing a single entry point for session lifecycle control.
Step 2: SessionStorage abstraction
Create a storage interface so the current database-backed implementation is one storage provider among others.
This is primarily an architectural boundary. It is not required to add new storage providers in the first implementation.
Step 3: Session mode setting
Add a system setting such as:
alwayslazy
Default must remain always for backward compatibility.
Deferred Session Creation behavior
In lazy mode, the system should not create a session during bootstrap if the current request does not need one.
A session should be started only when the code actually requires it, for example:
- login or authentication,
- explicit session writes,
- CSRF/token creation,
- flash messages,
- manager-side state that depends on sessions,
- other explicit session operations.
Anonymous page views that do not use session state should complete without creating a new session row.
Why this should be split into multiple PRs
Combining abstraction and behavior change in one PR would make review harder and increase regression risk.
The safer route is:
- Document the current lifecycle.
- Introduce abstractions without changing behavior.
- Add deferred session creation on top of the abstraction.
This makes it easier for maintainers to review each step independently.
Expected Benefits
- fewer unnecessary session rows,
- reduced growth of
modSession, - less database work for anonymous traffic,
- easier garbage collection and maintenance,
- cleaner session architecture,
- future storage backends become easier to introduce.
Risks and Open Questions
- Some Extras may rely on session side effects happening very early.
- PHP session behavior places constraints on when a session can start.
- There may be code paths that assume
$_SESSIONis already available. - Manager authentication flows must remain unchanged.
- We need to confirm how much of the current session lifecycle can be deferred safely.
This is why the research step is essential before coding.
Proposed Acceptance Criteria
PRD-1
- Runtime behavior is unchanged.
- Session operations go through a centralized abstraction.
- All existing tests pass.
- No unrelated code is modified.
PRD-2
alwaysremains the default mode.lazymode prevents unnecessary anonymous session creation.- Authentication and manager behavior remain unchanged.
- No breaking changes are introduced for existing sites.
Request for Feedback
Before starting implementation, I would appreciate feedback from the maintainers:
- Does this staged approach fit the direction of MODX core?
- Would introducing a
SessionManagerabstraction be acceptable as a standalone refactoring? - Are there any known architectural constraints around the current session lifecycle that should be investigated first?
- Is there any existing session infrastructure that should be reused instead of introducing a new abstraction?
Suggested Next Step
If there is interest in this direction, I will first prepare a documentation-only PR that maps the current session lifecycle, bootstrap sequence, authentication flow, and session dependencies before proposing any implementation changes.
This will allow the architecture to be reviewed first, reducing the risk of unnecessary implementation work and making subsequent pull requests smaller and easier to review.