express-session-rethinkdb-esm
v1.0.1
Published
[RethinkDB](https://rethinkdb.com/) database adapter for [`express-session`](https://github.com/expressjs/session) middleware for [ExpressJS](https://expressjs.com/).
Readme
express-session-rethinkdb-esm
RethinkDB database adapter for express-session middleware for ExpressJS.
Thank you to everyone writing express-session drivers out there for the boilerplate and inspiration.
Installation
npm install express-session-rethinkdb-esm --save
Constructor Options
client: Required — RethinkDB import.
connGetter: Required — A function that returns the current RethinkDB connection. Called on every operation so the store always uses the live connection after a reconnect.
table: RethinkDB table to store sessions in (default: sessions).
ttl: Time in milliseconds to expire sessions (default: two weeks).
gcProbability: Probability (0–1) that each set() call triggers a background sweep deleting all expired sessions (default: 0.01). Set to 0 to disable.
Usage
// rethinkdb
import r from 'rethinkdb'
let rc = await r.connect({ host })
// express
import express from 'express'
import session from 'express-session'
import _init_rdb_express_session_store from 'express-session-rethinkdb-esm'
const app = express()
const RethinkdbSessionStore = _init_rdb_express_session_store({ session })
app.use( session({
store: new RethinkdbSessionStore({ client: r, connGetter: () => rc })
}) )connGetter and Reconnection
Pass a getter function rather than a static reference so the store always uses the current live connection:
let rc = await r.connect({ host })
// reconnect handler — rc is reassigned on reconnect
rc.on( 'close', async () => {
rc = await r.connect({ host })
} )
// store dereferences rc at call time — no manual patching needed
const store = new RethinkdbSessionStore({ client: r, connGetter: () => rc })Wait on Readiness
Use the ready property to wait for store initialization (table creation and index setup):
// Async/Await
await rethinkdbSessionStoreInstance.readySession Cleanup
Expired sessions are cleaned up automatically:
- Lazy deletion: When
get()finds an expired session, it deletes it in the background before returningnull. - Probabilistic GC: Each
set()call has agcProbabilitychance (default 1%) of sweeping all expired sessions. This handles abandoned sessions that are never read again.
No timers or manual vacuum calls are required for normal operation.
vacuum() — Admin Escape Hatch
vacuum() immediately deletes all expired sessions. Useful as a one-off maintenance operation (e.g. after upgrading from a version that had the broken vacuum query):
await store.vacuum()Running Tests
Integration tests run against a real RethinkDB instance. A dedicated sessions_test table is created and dropped automatically.
# start a throwaway RethinkDB
docker run --rm -p 28015:28015 rethinkdb:2.4.3
# install devDependencies and run tests
npm install
npm test
# custom host/port
RETHINKDB_HOST=myhost RETHINKDB_PORT=28015 npm test1.0.0 Changelog
conn replaced by connGetter
Previously the constructor accepted a static connection reference. It now accepts a getter function that is called on every operation, so the store always uses the current live connection after a reconnect.
// before
new RethinkdbSessionStore({ client: r, conn: rc })
// after
new RethinkdbSessionStore({ client: r, connGetter: () => rc })If you were manually patching the connection after reconnects (e.g. store.conn = root_rc in a reconnect handler), that workaround can be removed.
vacuum() query fixed
The previous implementation deleted sessions with expires < (now - ttl) instead of expires < now. Expired sessions were never actually cleaned up. The query now correctly deletes everything with an expiry in the past.
set() and touch() now surface errors without a callback
Previously, errors in set() and touch() were silently swallowed when called without a callback. They now throw, consistent with all other methods.
destroy() no longer crashes without a callback
Previously destroy() always called cb( err ) unconditionally, throwing TypeError: cb is not a function if no callback was provided. Fixed.
New: lazy deletion on get()
When a session is found but has expired, it is deleted from the database in the background before returning null.
New: probabilistic GC on set() (default 1%)
On each set() call, there is a configurable probability (default gcProbability: 0.01) that a background sweep deletes all expired sessions. Set to 0 to disable.
Initialization errors now propagate via EventEmitter
Previously, if the DB was unreachable at startup, the constructor's internal _init call rejected silently (UnhandledPromiseRejection) and store.ready hung forever. Init errors now route through the standard Node.js error channel. Attach an 'error' listener if you need to handle startup failures explicitly:
store.on( 'error', err => {
console.error( 'Session store init failed:', err )
process.exit( 1 )
} )Unknown constructor options no longer clobber internals
Previously all options were merged onto the instance via Object.assign, meaning any option key matching a class member (_t, _init, ready, get, set, etc.) would silently overwrite it. The constructor now extracts only the five known keys (client, connGetter, table, ttl, gcProbability). Unknown keys are ignored.
