npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@itrocks/fastify-file-session-store

v0.4.1

Published

Simple session data persistence for Fastify using JSON files

Readme

npm version npm downloads GitHub issues discord

fastify-file-session-store

Simple session data persistence for Fastify using JSON files.

This documentation was written by an artificial intelligence and may contain errors or approximations. It has not yet been fully reviewed by a human. If anything seems unclear or incomplete, please feel free to contact the author of this package.

Installation

npm i @itrocks/fastify-file-session-store @fastify/session fastify

@itrocks/fastify-file-session-store does not install fastify or @fastify/session as direct dependencies of your application: you must declare them yourself in your project.

Usage

FileStore is an implementation of SessionStore for @fastify/session that stores each session as a JSON file on disk. It is intended for simple Fastify applications, where lightweight session persistence is enough and you do not want to set up a dedicated database.

It also implements the transport-neutral @itrocks/session store contract so applications can list and revoke authenticated sessions without depending on Fastify.

Minimal example

import Fastify from 'fastify'
import fastifySession from '@fastify/session'
import { FileStore } from '@itrocks/fastify-file-session-store'

const app = Fastify()

app.register(fastifySession, {
  secret: 'a very secret key with at least 32 characters',
  cookie: {
    secure: false, // set to true when running behind HTTPS
  },
  store: new FileStore('./sessions'),
})

app.get('/', async (request, reply) => {
  request.session.views = (request.session.views ?? 0) + 1
  return { views: request.session.views }
})

app.listen({ port: 3000 })
  .then(() => console.log('Server listening on http://localhost:3000'))

Complete and realistic example

The following example shows a more advanced configuration using node:path to define a sessions directory, basic error handling, and reuse of the same store across several routes.

import Fastify from 'fastify'
import fastifySession from '@fastify/session'
import { FileStore } from '@itrocks/fastify-file-session-store'
import { join, normalize } from 'node:path'

const app = Fastify({ logger: true })

// Absolute path to the sessions directory, for example in a data folder
const sessionDir = normalize(join(__dirname, '../data/sessions'))

app.register(fastifySession, {
  secret: process.env.SESSION_SECRET ?? 'change-me-in-production',
  cookie: {
    path: '/',
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'lax',
  },
  store: new FileStore(sessionDir),
})

app.get('/login', async (request, reply) => {
  const userId = request.query.userId ?? 'guest'
  request.session.user = { id: userId }
  return { ok: true, user: request.session.user }
})

app.get('/me', async (request, reply) => {
  if (!request.session.user) {
    reply.code(401)
    return { error: 'Not authenticated' }
  }
  return { user: request.session.user }
})

app.get('/logout', async (request, reply) => {
  // Destroy the session in the store and in the cookie
  await request.session.destroy()
  return { ok: true }
})

app.listen({ port: 3000 }).catch((error) => {
  app.log.error(error, 'Cannot start server')
  process.exit(1)
})

API

class FileStore implements SessionStore

Implementation of SessionStore (the @fastify/session interface) that saves sessions into individual JSON files.

Each session id corresponds to a file in the directory provided to the constructor. Reads return detached snapshots. Per-session locks coordinate authoritative reads, writes and revocation.

new FileStore(directory: string)

  • directory: path to the directory where session files will be created. It can be relative to the current process directory or absolute. The directory must exist and be readable and writable by the Node.js process.

Returns a FileStore instance to pass to the store option of @fastify/session.

sessionFile(sessionId: string): string

Builds the full path to the session file corresponding to sessionId. This method is exposed publicly but is generally only useful if you want to diagnose or manipulate the session files manually.

set(sessionId: string, session: Session, callback: (error?: any) => void): void

Method called by @fastify/session when a session must be stored.

  • sessionId: unique identifier of the session.
  • session: Session object provided by Fastify, serializable to JSON.
  • callback(error?): function to call once the write is finished or in case of error.

The store merges changes made since this request loaded its snapshot, then atomically replaces the JSON file. The callback runs only after persistence succeeds. Nested mutations are detected without retaining live cache objects.

compareAndSet(sessionId, expectedGeneration, session, callback): void

Implements the generation-checked write required by @fastify/session 11.1.6. The callback receives ENOENT when the stored session is missing, expired, revoked or belongs to a different generation. Other storage errors are preserved. Generation checks and persistence share the same per-session lock as transactions and revocation; acknowledgement follows the atomic file replacement.

Saves of the same generation merge request changes. Regeneration replaces the business state and invalidates previous request leases while retaining Fastify's stable storage identifier. Legacy files without Fastify generation metadata use their storage identifier as the expected generation, allowing existing cookies to be upgraded. Fastify's immutable session metadata is retained without assigning to its read-only property and is excluded from business snapshots and session management listings. The store also supports @fastify/session 11.1.4.

get(sessionId: string, callback: (error: any, session?: Session | null) => void): void

Method called by @fastify/session to load an existing session.

  • sessionId: identifier of the session to read.
  • callback(error, session?):
    • error is null or undefined when everything went well;
    • session is:
      • the Session object that was found;
      • null/undefined when no valid session exists for that id.

The store reads the corresponding session file, parses it as JSON and returns the session.

Missing or expired files return no session. Other read/parse failures reach the callback as errors; corrupt or unavailable storage is never treated as permission to recreate a missing generation.

destroy(sessionId: string, callback: (error?: any) => void): void

Removes the corresponding session from disk under the same lock as writes.

  • sessionId: identifier of the session to destroy.
  • callback(error?): function called after the deletion, or with an error if something went wrong.

This method is typically called when a user logs out or when the session expires.

list(): Promise<StoredSession[]>

Returns every readable stored session with its identifier and file modification date. Invalid files and files removed concurrently are ignored. A missing session directory produces an empty list.

revoke(sessionId: string): Promise<void>

Removes a session from memory and disk. Revocation is idempotent: an already absent session is treated as successfully revoked.

Typical use cases

  • Simple Fastify projects without a dedicated session database: you want session persistence across server restarts, but you do not want to set up Redis, a SQL database or another external service.
  • Development or demo environments: file-based persistence is convenient to quickly test an application or share a local demo.
  • Single-instance applications: when your application runs on a single machine (or with a shared filesystem) and you do not need session consistency across several nodes.
  • Session debugging: because sessions are stored as JSON files, you can open the file corresponding to a given sessionId to inspect or debug the session state.

Transactions and generation checks

transact<T>(sessionId, session, operation): Promise<T> reloads the authoritative snapshot under a session-wide lock, merges only the request's changes, invokes operation(data), then atomically persists the result before acknowledging it. An operation that throws commits nothing. File failures leave the previous snapshot intact and release coordination. refresh(sessionId, session) reloads a live request session; it rejects a missing, revoked or expired generation. SessionExpiredError carries code SESSION_STALE for these rejections.

Generation metadata is reserved internally. Session management list() exposes business data without that marker. Snapshots are detached, scoped to the store instance and attached to request leases using weak references. The lock registry contains coordination promises only and removes completed entries. All set, compareAndSet, transact, refresh, get, revoke and destroy operations share it. Absolute expiry is checked again before a transaction commits. Session file replacement is atomic within the same directory; directories/files use modes 0700/0600.

This contract supports one store instance per session directory in a single server process. It does not provide cross-process locking. Separate directory instances remain isolated; a new instance can read durable files on restart.

npm test exercises the store and the installed Fastify session plugin. Set FASTIFY_SESSION_MODULE to another installed @fastify/session package directory to run the HTTP contract against that version without replacing application packages.