mrkeyoor.com_
Sat 08 Aug 21:59 UTC
npmWeb Backendupdated 08 Aug 2026

nocache

nocache is a tiny Express and Connect middleware factory that writes three fixed response headers: `Cache-Control: no-store, no-cache, must-revalidate, proxy-revalidate`, `Expires: 0`, and `Surrogate-Control: no-store`. It then calls the next middleware. The goal is to discourage browsers, shared proxies, and surrogate caches from storing or reusing a response. It has no policy options, route matcher, cache purge mechanism, or response-body logic, so placement in your middleware stack determines exactly which responses it affects.

Verdict

A clear, low-risk helper when a route truly must not be stored and the fixed policy is exactly right. Do not install it as a substitute for designing cache policy, and do not mount it across cacheable public content by default.

API stability5/5The public contract is a zero-argument factory returning standard Connect middleware, and the implementation is only three setHeader calls followed by next. Version 4 removed old compatibility baggage but the current surface has no option object or secondary exports to churn. The bundled declaration matches the source exactly, so existing Express and Connect call sites have very little upgrade-sensitive behavior beyond the declared Node floor.
Docs3/5The README is short but accurate: it shows the correct factory call, lists all three headers and their exact values, and says the goal is to try to disable client-side caching. It does not discuss middleware order, route scoping, ETag and Last-Modified, previously cached objects, CDN overrides, Clear-Site-Data, TypeScript, or the performance cost of global use, leaving the operational decisions to HTTP knowledge outside the package.
Maintenance4/5The current 4.0.0 release was published on 2023-06-01, and GitHub reports a push on 2026-06-25 to an unarchived repository with one open issue and PR combined. The package is owned under Helmet and its source, types, linting, and test surface are tiny. Releases are naturally infrequent because the behavior is fixed; the remaining concern is that runtime and HTTP ecosystem changes may not produce visible package releases.
Ecosystem4/5The package recorded 3,483,006 downloads in the measured week, follows the ubiquitous Connect middleware signature, works with Express routers, and comes from the Helmet organization. It adds no runtime dependencies and bundles declarations. Its ecosystem role is narrow rather than extensible: there are no adapters, options, plugins, ESM build, or CDN integrations, and many applications can express the same policy in three local header assignments.

Use it if

  • You need a consistent no-store policy on a small set of sensitive Express or Connect routes
  • You are temporarily stopping reuse of a changing response while you repair a bad caching policy
  • You want a dependency-free middleware with bundled TypeScript declarations rather than repeating three headers in several routers
  • You have tests proving no later middleware or CDN configuration overwrites the headers
Skip it if

Setup reality

`npm install nocache` installs five files and no runtime dependencies, peer dependencies, native code, environment variables, or configuration. Version 4.0.0 supports Node 16 or newer, ships CommonJS, and includes a TypeScript declaration based on Node's IncomingMessage and ServerResponse types. Call the factory once and mount the returned middleware: `app.use(nocache())`. Calling `app.use(nocache)` is wrong because Express will pass request arguments to the factory, which returns another function instead of finishing the request. The package exposes no options. It always calls `setHeader` for the same Surrogate-Control, Cache-Control, and Expires values, overwriting values set earlier. Middleware or route code that sets those headers later wins, so order is part of correctness. Mounting it globally also affects HTML, JSON, downloads, error pages, and static responses that pass through it; route or router scope is usually safer. It does not remove ETag or Last-Modified, though `no-store` tells compliant caches not to store the response. It does not add Clear-Site-Data, send a CDN purge request, vary by authentication state, or distinguish shared from private caches. A prior response may already exist in a browser or edge cache, and platform-specific CDN rules can ignore or replace origin directives. Test the final response at the public edge, not just inside Express. For sensitive data, cache headers complement transport security, authorization, correct logout behavior, and avoiding secrets in URLs; they do not erase browser history or copies held elsewhere. Because the middleware runs before the response is produced, it also adds the headers to errors generated later in the chain unless an error handler overwrites them.

Patterns

Apply no-store headers to every later routedisable-cache-globally

const express = require('express');
const nocache = require('nocache');

const app = express();
app.use(nocache());
app.get('/account', (req, res) => res.json({ id: req.user.id }));

Global mounting also disables caching for public and static responses that pass through it. Prefer narrower scope unless every response is sensitive.

Disable caching on one sensitive routeprotect-sensitive-route

const nocache = require('nocache');

app.get('/account/export', nocache(), async (req, res) => {
  const exportData = await buildAccountExport(req.user.id);
  res.json(exportData);
});

This is usually safer than a global middleware because unrelated assets and public GET endpoints retain their own cache policy.

Apply the policy to an authenticated routerprotect-router

const express = require('express');
const nocache = require('nocache');

const account = express.Router();
account.use(requireUser);
account.use(nocache());
account.get('/profile', showProfile);
account.post('/logout', logOut);
app.use('/account', account);

Place authentication and no-cache policy deliberately. Headers can still be present on authentication errors depending on middleware order.

Disable caching only for signed-in usersapply-conditionally

const nocache = require('nocache');
const noCache = nocache();

app.use((req, res, next) => {
  if (req.user) return noCache(req, res, next);
  next();
});

Shared-cache safety also depends on Vary and authentication-aware CDN configuration. Conditional origin headers alone may not repair an unsafe edge cache key.

Set headers on sensitive error responsesprotect-error-responses

const nocache = require('nocache');

app.get('/reset-password', nocache(), async (req, res, next) => {
  try {
    res.render('reset', await loadResetState(req.query.token));
  } catch (error) {
    next(error);
  }
});

The headers remain on downstream errors unless an error handler replaces them, which is useful when error bodies can also contain private data.

Test the final Express headersverify-response-headers

const request = require('supertest');

it('prevents storage of account responses', async () => {
  const response = await request(app).get('/account/profile').expect(200);
  expect(response.headers['cache-control'])
    .toBe('no-store, no-cache, must-revalidate, proxy-revalidate');
  expect(response.headers['surrogate-control']).toBe('no-store');
  expect(response.headers.expires).toBe('0');
});

An application test catches later middleware overwrites. Also inspect the public CDN response because edge configuration can change headers after Express.

Mount the returned middleware, not the factoryavoid-factory-mistake

const nocache = require('nocache');

app.use(nocache()); // correct
// app.use(nocache); // wrong

nocache takes no request arguments and returns the real middleware. Forgetting parentheses can leave the request unfinished.

Keep cacheable routes outside its scopepreserve-route-cache-policy

const nocache = require('nocache');

app.use('/private', nocache(), privateRouter);
app.use('/assets', express.static('public', {
  maxAge: '1y',
  immutable: true,
}));

Mount order and path scope keep long-lived asset caching intact. Confirm no parent router applies nocache before both branches.

Understand last-writer-wins header orderoverride-after-nocache

const nocache = require('nocache');

app.get('/status', nocache(), (req, res) => {
  res.set('Cache-Control', 'public, max-age=30');
  res.json({ ok: true });
});

This route overwrites nocache's Cache-Control value but leaves Expires and Surrogate-Control unchanged, producing a contradictory policy. Avoid mixed writers.

Use the middleware in a Connect stackuse-with-connect

const connect = require('connect');
const nocache = require('nocache');

const app = connect();
app.use('/session', nocache());
app.use('/session', (req, res) => {
  res.end('private');
});

The declaration uses Node IncomingMessage and ServerResponse, so no Express-only response methods are required.

Use three local headers instead of installing itset-headers-without-dependency

function noStore(req, res, next) {
  res.setHeader('Surrogate-Control', 'no-store');
  res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
  res.setHeader('Expires', '0');
  next();
}

This is the complete 4.0.0 behavior. A local helper is reasonable when adding a package for three fixed lines is not worth supply-chain surface.

Request a browser cache clear on a dedicated responseclear-browser-cache-separately

const nocache = require('nocache');

app.post('/session/logout', nocache(), (req, res) => {
  res.setHeader('Clear-Site-Data', '"cache"');
  req.session.destroy(() => res.sendStatus(204));
});

nocache does not emit Clear-Site-Data. Browser support and scope vary, and this still does not purge CDN objects or replace correct logout logic.

Alternatives

PackageRegistryPick it when
express-cache-controllernpmYou need Express middleware with configurable Cache-Control directives instead of one fixed no-store policy
helmetnpmYou need a broader set of Express security headers and are willing to set cache policy separately
freshnpmYou need to decide whether a request is fresh from ETag and Last-Modified validators rather than disabling caching
cache-control-parsernpmYou need to parse and inspect Cache-Control directives as data instead of writing fixed headers