Express Session Middleware
express-session is a robust and widely-used session middleware for Express.js applications, currently stable at version 1.19.0. It provides server-side session storage, managing session IDs via cookies while keeping the actual session data on the server, which is a key security differentiator compared to client-side cookie storage. While the core package offers a default `MemoryStore` for development and debugging, it explicitly warns against its use in production due to memory leak risks and lack of scalability, promoting a rich ecosystem of compatible external session stores. The project maintains a steady release cadence, with recent updates focusing on features like dynamic cookie options, improved security tooling, and dependency updates, ensuring ongoing compatibility and enhancements for Node.js environments (supporting Node.js >= 0.8.0). It has evolved to directly manage session cookies, making the `cookie-parser` middleware optional and recommending careful use if both are present to avoid secret mismatches.
Common errors
-
Error: secret must be a string or array of strings
cause The `secret` option, which is mandatory for session signing, was either omitted or provided with an invalid type (e.g., `null`, `undefined`, a number).fixProvide a strong, unpredictable string or an array of strings as the `secret` value in the `session()` options. It should be stored in an environment variable for security. -
TypeError: session is not a function
cause This typically occurs when attempting to use `express-session` as a direct middleware function, rather than calling the imported module to get the middleware factory. This is often an ESM `import` or CommonJS `require` misuse.fixEnsure you are calling the imported `session` module to create the middleware: `app.use(session({ ... }))`. For CommonJS: `const session = require('express-session');`. For ESM: `import session from 'express-session';`. -
Warning: connect.session() MemoryStore is not designed for a production environment, as it will leak memory, and will not scale past a single process.
cause This warning explicitly states that the default `MemoryStore` is being used in an environment that is likely production, which will lead to memory leaks and scalability issues.fixReplace the default `MemoryStore` with a production-grade, persistent session store like `connect-redis`, `connect-mongo`, or `memorystore`. -
CookieParseError: Invalid cookie header
cause A conflict or misconfiguration between `express-session` and `cookie-parser`, particularly if both are used with different `secret` options, or if `cookie-parser` is used redundantly as `express-session` handles cookie parsing internally.fixRemove `cookie-parser` if `express-session` is sufficient for your cookie needs. If `cookie-parser` is still needed for other reasons, ensure both `express-session` and `cookie-parser` use the exact same `secret` value. -
UnhandledPromiseRejectionWarning: Error: Bad session data
cause The session store returned corrupted or unparseable session data, or an internal error occurred during session deserialization. This can sometimes happen with store migrations or data integrity issues.fixInspect the session store for malformed data. If using a custom store, verify its `get` and `set` methods. If using an existing store, check for recent updates to `express-session` or the store implementation that might address data handling bugs.
Warnings
- gotcha The default `MemoryStore` provided by `express-session` is explicitly not designed for production environments. It is known to leak memory under most conditions and does not scale past a single process, making it suitable only for debugging and development.
- gotcha Since version 1.5.0, `express-session` directly reads and writes cookies on `req`/`res`. Using `cookie-parser` middleware concurrently can lead to issues, especially if the `secret` used by `express-session` differs from that used by `cookie-parser`.
- gotcha When configuring cookie options, if both `expires` and `maxAge` are set, the last one defined in the `cookie` object will take precedence. It is generally recommended to use only `maxAge`.
- deprecated The `resave` option's default value of `true` has been deprecated and will change in future versions. Setting `resave: true` can create race conditions in certain session stores.
- breaking The `cookie` dependency was updated to `0.6.0` in `express-session` v1.18.0, which included a fix to reject invalid dates for the `expires` option. Applications that might have implicitly handled or passed malformed dates to `expires` could experience errors.
- gotcha Setting `cookie.httpOnly` to `false` (it defaults to `true`) allows client-side JavaScript to access the session cookie via `document.cookie`. This significantly increases the risk of Cross-Site Scripting (XSS) attacks leading to session hijacking.
Install
-
npm install express-session -
yarn add express-session -
pnpm add express-session
Imports
- session
import { session } from 'express-session'import session from 'express-session'
- session
const { session } = require('express-session')const session = require('express-session') - SessionStore
import { SessionStore } from 'express-session'; // Incorrect export name for typeimport { Store } from 'express-session'; // For type hinting custom stores
Quickstart
const express = require('express');
const session = require('express-session');
const app = express();
const port = 3000;
// WARNING: The default MemoryStore is NOT production-ready.
// For production, use a compatible session store like connect-redis, connect-mongo, or memorystore.
// For a list of stores, see compatible session stores section in the README.
app.use(session({
secret: process.env.SESSION_SECRET ?? 'a very strong secret key that should be in an environment variable', // ALWAYS use a strong, environment-variable-backed secret
resave: false, // Don't save session if unmodified
saveUninitialized: true, // Save new but uninitialized sessions (e.g., before user logs in)
cookie: {
secure: process.env.NODE_ENV === 'production', // Use secure cookies in production (requires HTTPS)
httpOnly: true, // Prevent client-side JavaScript access to cookie (mitigates XSS)
maxAge: 24 * 60 * 60 * 1000 // Session expires after 24 hours (in milliseconds)
}
}));
app.get('/', (req, res) => {
if (req.session.views) {
req.session.views++;
res.send(`<h1>Welcome back!</h1><p>You have visited this page ${req.session.views} times.</p><p>Your session ID is: ${req.sessionID}</p>`);
} else {
req.session.views = 1;
res.send(`<h1>Hello, New User!</h1><p>You have visited this page ${req.session.views} time.</p><p>Your session ID is: ${req.sessionID}</p>`);
}
});
app.listen(port, () => {
console.log(`Server listening at http://localhost:${port}`);
console.log('Try visiting a few times and then refresh after some time to see the session count.');
console.log('For production, ensure `secure: true` for cookies and that your app runs over HTTPS.');
});