A simple LiteSpeed Cache helper package for NestJS applications.
- Run your NestJS app behind LiteSpeed/OpenLiteSpeed.
- Ensure LiteSpeed cache is enabled and writable.
npm i lscache-nestjs// main.ts
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";
import { lscacheMiddleware } from "lscache-nestjs";
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const applyLSCache = lscacheMiddleware({
shouldCache: (req) => req.method === "GET",
cookieBypassList: ["session", "next-auth.session-token"],
privateOptions: {
mode: "cache",
maxAge: 180
},
publicOptions: {
maxAge: 60
}
});
app.use((req, res, next) => {
applyLSCache(req, res);
next();
});
await app.listen(3000);
}
bootstrap();If you want different cache behavior by URL, create multiple middleware instances and apply by route:
// main.ts
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";
import { lscacheMiddleware } from "lscache-nestjs";
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const mainPageCache = lscacheMiddleware({
publicOptions: {
maxAge: 120,
tags: ["home"]
}
});
const postPageCache = lscacheMiddleware({
publicOptions: {
maxAge: 300,
tags: ["post"]
}
});
app.use((req, res, next) => {
if (req.path === "/") {
mainPageCache(req, res);
} else if (req.path.startsWith("/post")) {
postPageCache(req, res);
}
next();
});
await app.listen(3000);
}
bootstrap();// main.ts
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";
import { lscacheMiddleware } from "lscache-nestjs";
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const cache120 = lscacheMiddleware({
publicOptions: { maxAge: 120, tags: ["blog"] }
});
const cache600 = lscacheMiddleware({
publicOptions: { maxAge: 600, tags: ["post"] }
});
const noCache = lscacheMiddleware({
publicOptions: { maxAge: 0 }
});
app.use((req, res, next) => {
if (req.path === "/blog") {
cache120(req, res);
} else if (req.path.startsWith("/post/")) {
cache600(req, res);
} else if (req.path.startsWith("/admin")) {
noCache(req, res);
}
next();
});
await app.listen(3000);
}
bootstrap();/admin and /admin/* are always set to:
x-litespeed-cache-control: no-cache
Default public response header:
x-litespeed-cache-control: public,max-age=60
When request has a bypass cookie (for example session=...) and privateOptions.mode is "cache":
x-litespeed-cache-control: private,max-age=180
const applyLSCache = lscacheMiddleware({
cookieBypassList: ["session"],
privateOptions: {
mode: "cache",
maxAge: 180
}
});
app.use((req, res, next) => {
if (req.path === "/contact") {
applyLSCache(req, res);
}
next();
});Result on /contact when session cookie exists:
x-litespeed-cache-control: private,max-age=180
const applyLSCache = lscacheMiddleware({
publicOptions: {
maxAge: 300,
tags: ["blog", "frontpage"]
}
});Result:
x-litespeed-cache-control: public,max-age=300x-litespeed-tag: blog,frontpage
const applyLSCache = lscacheMiddleware({
publicOptions: { maxAge: 0 }
});
// or
const applyLSCache2 = lscacheMiddleware({
publicOptions: { cacheability: "no-cache" }
});Both set:
x-litespeed-cache-control: no-cache
// lscache.controller.ts
import { Controller, Get, Res } from '@nestjs/common';
import type { Response } from 'express';
@Controller('lscache')
export class LSCacheController {
@Get('purge-all')
purgeAll(@Res() res: Response) {
res.setHeader('X-LiteSpeed-Purge', '*');
return res.status(200).json({
ok: true,
purge: 'all',
});
}
}Test purge-all URL:
curl -k -X POST https://your-site.com/lscache/purge-allYou can also use helper functions (verifyPurgeRequest, buildPurgeTags, purgeLSCache, purgeAllLSCache, purgeLSCacheByTags) for custom purge endpoint flows.
Cached case h2load -n 50000 -c 50 https://x.x.x.x/blog
finished in 6.18s, 8091.08 req/s, 399.64KB/s requests: 50000 total, 50000 started, 50000 done, 50000 succeeded, 0 failed, 0 errored, 0 timeout status codes: 50000 2xx, 0 3xx, 0 4xx, 0 5xx
No cache case h2load -n 50000 -c 50 https://x.x.x.x/blog
finished in 16.68s, 2998.27 req/s, 146.51KB/s requests: 50000 total, 50000 started, 50000 done, 50000 succeeded, 0 failed, 0 errored, 0 timeout status codes: 50000 2xx, 0 3xx, 0 4xx, 0 5xx
LiteSpeed/OpenLiteSpeed comes with python in detached mode by default, so you will need to restart python with following command to make any new settings take effect:
pkill lsnode