{"id":13423795,"url":"https://github.com/hoangvvo/next-session","last_synced_at":"2025-05-16T09:00:29.003Z","repository":{"id":35029822,"uuid":"197891718","full_name":"hoangvvo/next-session","owner":"hoangvvo","description":"Simple promise-based session middleware for Next.js, micro, Express, and more","archived":false,"fork":false,"pushed_at":"2024-05-23T06:21:26.000Z","size":2058,"stargazers_count":359,"open_issues_count":27,"forks_count":24,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-10T08:06:30.577Z","etag":null,"topics":["javascript","middleware","nextjs","promise","session"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/next-session","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hoangvvo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-20T06:49:22.000Z","updated_at":"2025-05-08T16:33:00.000Z","dependencies_parsed_at":"2024-06-18T13:41:12.170Z","dependency_job_id":"e6fd7d9d-a66d-41ce-b2e9-2a9fc4ca7f2f","html_url":"https://github.com/hoangvvo/next-session","commit_stats":{"total_commits":411,"total_committers":11,"mean_commits":37.36363636363637,"dds":0.4914841849148418,"last_synced_commit":"5615e7db93186b9948f33e9518fb0e0c826b8237"},"previous_names":[],"tags_count":37,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoangvvo%2Fnext-session","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoangvvo%2Fnext-session/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoangvvo%2Fnext-session/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hoangvvo%2Fnext-session/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hoangvvo","download_url":"https://codeload.github.com/hoangvvo/next-session/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254501548,"owners_count":22081526,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","middleware","nextjs","promise","session"],"created_at":"2024-07-31T00:00:42.709Z","updated_at":"2025-05-16T09:00:28.982Z","avatar_url":"https://github.com/hoangvvo.png","language":"TypeScript","readme":"# next-session\n\n[![npm](https://badgen.net/npm/v/next-session)](https://www.npmjs.com/package/next-session)\n[![minified size](https://badgen.net/bundlephobia/min/next-session)](https://bundlephobia.com/result?p=next-session)\n[![CircleCI](https://circleci.com/gh/hoangvvo/next-session.svg?style=svg)](https://circleci.com/gh/hoangvvo/next-session)\n[![codecov](https://codecov.io/gh/hoangvvo/next-session/branch/master/graph/badge.svg)](https://codecov.io/gh/hoangvvo/next-session)\n[![PRs Welcome](https://badgen.net/badge/PRs/welcome/ff5252)](CONTRIBUTING.md)\n\nLightweight _promise-based_ session middleware for [Next.js](https://github.com/zeit/next.js). Also works in [micro](https://github.com/zeit/micro) or [Node.js HTTP Server](https://nodejs.org/api/http.html), [Express](https://github.com/expressjs/express), and more.\n\n\u003e Also check out alternatives like [next-iron-session](https://github.com/vvo/next-iron-session). Take a look at [nextjs-mongodb-app](https://github.com/hoangvvo/nextjs-mongodb-app) to see this module in use.\n\n## Installation\n\n```sh\n// NPM\nnpm install next-session\n// Yarn\nyarn add next-session\n```\n\n## Usage\n\n:point_right: **Upgrading from v1.x to v2.x?** Please read the release notes [here](https://github.com/hoangvvo/next-session/releases/tag/v2.0.0)!\n\n:point_right: **Upgrading from v2.x to v3.x?** Please read the release notes [here](https://github.com/hoangvvo/next-session/releases/tag/v3.0.0)!\n\n:point_right: **Upgrading from v3.x to v4.x?** Please read the release notes [here](https://github.com/hoangvvo/next-session/releases/tag/v4.0.0)!\n\n**Warning** The default session store (if `options?.store` is `undefined`), `MemoryStore`, **DOES NOT** work in production or serverless environment. You must use a [Session Store](#session-store).\n\n```js\n// ./lib/get-session.js\nimport nextSession from \"next-session\";\nexport const getSession = nextSession(options);\n```\n\n### API Routes\n\n```js\nimport { getSession } from \"./lib/get-session.js\";\n\nexport default function handler(req, res) {\n  const session = await getSession(req, res);\n  session.views = session.views ? session.views + 1 : 1;\n  // Also available under req.session:\n  // req.session.views = req.session.views ? req.session.views + 1 : 1;\n  res.send(\n    `In this session, you have visited this website ${session.views} time(s).`\n  );\n}\n```\n\nUsage in API Routes may result in `API resolved without sending a response`. This can be solved by either adding:\n\n```js\nimport nextSession from \"next-session\";\nconst getSession = nextSession();\n\nexport default function handler(req, res) {\n  const session = await getSession(req, res);\n  /* ... */\n}\n\nexport const config = {\n  api: {\n    externalResolver: true,\n  },\n};\n```\n\n...or setting `options.autoCommit` to `false` and do `await session.commit()`.\n\n```js\nimport nextSession from \"next-session\";\nconst getSession = nextSession({ autoCommit: false });\n\nexport default function handler(req, res) {\n  const session = await getSession(req, res);\n  /* ... */\n  await session.commit();\n}\n```\n\n### getServerSideProps\n\n```js\nimport { getSession } from \"./lib/get-session.js\";\n\nexport default function Page({ views }) {\n  return (\n    \u003cdiv\u003eIn this session, you have visited this website {views} time(s).\u003c/div\u003e\n  );\n}\n\nexport async function getServerSideProps({ req, res }) {\n  const session = await getSession(req, res);\n  session.views = session.views ? session.views + 1 : 1;\n  // Also available under req.session:\n  // req.session.views = req.session.views ? req.session.views + 1 : 1;\n  return {\n    props: {\n      views: session.views,\n    },\n  };\n}\n```\n\n### Others\n\n[express](https://github.com/expressjs/express), [next-connect](https://github.com/hoangvvo/next-connect)\n\n```js\nconst express = require(\"express\");\nconst app = express();\napp.use(async (req, res, next) =\u003e {\n  await getSession(req, res); // session is set to req.session\n  next();\n});\napp.get(\"/\", (req, res) =\u003e {\n  req.session.views = req.session.views ? req.session.views + 1 : 1;\n  res.send(\n    `In this session, you have visited this website ${req.session.views} time(s).`\n  );\n});\n```\n\n[micro](https://github.com/vercel/micro), [Vercel Serverless Functions](https://vercel.com/docs/functions/introduction)\n\n```js\nmodule.exports = (req, res) =\u003e {\n  const session = await getSession(req, res);\n  res.end(\n    `In this session, you have visited this website ${session.views} time(s).`\n  );\n};\n```\n\n[Node.js HTTP Server](https://nodejs.org/api/http.html)\n\n```js\nconst http = require(\"http\");\n\nconst server = http.createServer(async (req, res) =\u003e {\n  const session = await getSession(req, res);\n  res.end(`In this session, you have visited this website ${session.views} time(s).`;\n});\nserver.listen(8080);\n```\n\n## Options\n\n`next-session` accepts the properties below.\n\n| options         | description                                                                                                                                  | default                                  |\n| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- |\n| name            | The name of the cookie to be read from the request and set to the response.                                                                  | `sid`                                    |\n| store           | The session store instance to be used. **Required** to work in production!                                                                   | `MemoryStore`                            |\n| genid           | The function that generates a string for a new session ID.                                                                                   | [`nanoid`](https://github.com/ai/nanoid) |\n| encode          | Transforms session ID before setting cookie. It takes the raw session ID and returns the decoded/decrypted session ID.                       | undefined                                |\n| decode          | Transforms session ID back while getting from cookie. It should return the encoded/encrypted session ID                                      | undefined                                |\n| touchAfter      | Only touch after an amount of time **(in seconds)** since last access. Disabled by default or if set to `-1`. See [touchAfter](#touchAfter). | `-1` (Disabled)                          |\n| autoCommit      | Automatically commit session. Disable this if you want to manually `session.commit()`                                                        | `true`                                   |\n| cookie.secure   | Specifies the boolean value for the **Secure** `Set-Cookie` attribute.                                                                       | `false`                                  |\n| cookie.httpOnly | Specifies the boolean value for the **httpOnly** `Set-Cookie` attribute.                                                                     | `true`                                   |\n| cookie.path     | Specifies the value for the **Path** `Set-Cookie` attribute.                                                                                 | `/`                                      |\n| cookie.domain   | Specifies the value for the **Domain** `Set-Cookie` attribute.                                                                               | unset                                    |\n| cookie.sameSite | Specifies the value for the **SameSite** `Set-Cookie` attribute.                                                                             | unset                                    |\n| cookie.maxAge   | **(in seconds)** Specifies the value for the **Max-Age** `Set-Cookie` attribute.                                                             | unset (Browser session)                  |\n\n### touchAfter\n\nTouching refers to the extension of session lifetime, both in browser (by modifying `Expires` attribute in [Set-Cookie](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie) header) and session store (using its respective method) upon access. This prevents the session from being expired after a while.\n\nIn `autoCommit` mode (which is enabled by default), for optimization, a session is only touched, not saved, if it is not modified. The value of `touchAfter` allows you to skip touching if the session is still recent, thus, decreasing database load.\n\n### encode/decode\n\nYou may supply a custom pair of function that _encode/decode_ or _encrypt/decrypt_ the cookie on every request.\n\n```javascript\n// `express-session` signing strategy\nconst signature = require(\"cookie-signature\");\nconst secret = \"keyboard cat\";\nsession({\n  decode: (raw) =\u003e signature.unsign(raw.slice(2), secret),\n  encode: (sid) =\u003e (sid ? \"s:\" + signature.sign(sid, secret) : null),\n});\n```\n\n## API\n\n### session object\n\nThis allows you to **set** or **get** a specific value that associates to the current session.\n\n```javascript\n//  Set a value\nif (loggedIn) session.user = \"John Doe\";\n//  Get a value\nconst currentUser = session.user; // \"John Doe\"\n```\n\n### session.touch()\n\nManually extends the session expiry by maxAge. **Note:** You must still call session.commit() if `autoCommit = false`.\n\n```js\nsession.touch();\n```\n\nIf `touchAfter` is set with a non-negative value, this will be automatically called accordingly.\n\n### session.destroy()\n\nDestroy to current session and remove it from session store.\n\n```javascript\nif (loggedOut) await session.destroy();\n```\n\n### session.commit()\n\nSave the session and set neccessary headers. Return Promise. It must be called before _sending the headers (`res.writeHead`) or response (`res.send`, `res.end`, etc.)_.\n\nYou **must** call this if `autoCommit` is set to `false`.\n\n```javascript\nsession.hello = \"world\";\nawait session.commit();\n// always calling res.end or res.writeHead after the above\n```\n\n### session.id\n\nThe unique id that associates to the current session.\n\n## Session Store\n\nThe session store to use for session middleware (see `options` above).\n\n### Implementation\n\nA compatible session store must include three functions: `set(sid, session)`, `get(sid)`, and `destroy(sid)`. The function `touch(sid, session)` is recommended. All functions must return **Promises**.\n\nRefer to [MemoryStore](https://github.com/hoangvvo/next-session/blob/master/src/memory-store.ts).\n\n_TypeScript:_ the `SessionStore` type can be used to aid implementation:\n\n```ts\nimport type { SessionStore } from \"next-session\";\n\nclass CustomStore implements SessionStore {}\n```\n\n### Compatibility with Express/Connect stores\n\n#### Promisify functions\n\nTo use [Express/Connect stores](https://github.com/expressjs/session#compatible-session-stores), you must promisify `get`, `set`, `destroy`, and (if exists) `touch` methods, possibly using [`util.promisify`](https://nodejs.org/dist/latest/docs/api/util.html#util_util_promisify_original).\n\nWe include the util [`promisifyStore`](./src/compat.ts#L29) in `next-session/lib/compat` to do just that:\n\n```js\nimport nextSession from \"next-session\";\nimport { promisifyStore } from \"next-session/lib/compat\";\nimport SomeConnectStore from \"connect-xyz\";\n\nconst connectStore = new SomeConnectStore();\n\nconst getSession = nextSession({\n  store: promisifyStore(connectStore),\n});\n```\n\nYou can use `expressSession` from `next-session/lib/compat` if the connect store has the following pattern.\n\n```javascript\nconst session = require(\"express-session\");\nconst RedisStore = require(\"connect-redis\")(session);\n\n// Use `expressSession` from `next-session/lib/compat` as the replacement\n\nimport nextSession from \"next-session\";\nimport { expressSession, promisifyStore } from \"next-session/lib/compat\";\nimport RedisStoreFactory from \"connect-redis\";\nimport Redis from \"ioredis\";\n\nconst RedisStore = RedisStoreFactory(expressSession);\nexport const getSession = nextSession({\n  store: promisifyStore(\n    new RedisStore({\n      client: new Redis(),\n    })\n  ),\n});\n```\n\n## Contributing\n\nPlease see my [contributing.md](CONTRIBUTING.md).\n\n## License\n\n[MIT](LICENSE)\n","funding_links":[],"categories":["Extensions","TypeScript","miscellaneous"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhoangvvo%2Fnext-session","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhoangvvo%2Fnext-session","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhoangvvo%2Fnext-session/lists"}