The npm ecosystem moves fast.
Libraries you'd never heard of six months ago are now in half the starters on GitHub.
Some are genuinely better. Some are hype.
Here are 10 that I think are actually worth your time in 2026.
TL;DR: Hono, Drizzle, Zod, Vitest, Effect, pompelmi, ofetch, unstorage, tsx, and oslo — one for almost every layer of your stack.
1. Hono — the web framework that actually stays out of your way
What it is:
A ultrafast, edge-first web framework. Runs on Cloudflare Workers, Deno, Bun, Node.js — all with the same API.
Why it matters:
Express is still fine, but it was designed before edge runtimes existed. Hono was built for the current landscape. The router is faster than Express in every benchmark I've seen, and the middleware system is dead simple.
import { Hono } from 'hono';
const app = new Hono();
app.get('/hello', (c) => c.json({ message: 'works everywhere' }));
export default app;
Links:
npm install hono — honojs.dev
2. Drizzle ORM — SQL without losing your mind
What it is:
A TypeScript ORM that writes SQL you'd actually recognize. Schema defined in TypeScript, queries look like SQL, types flow through automatically.
Why it matters:
Prisma is great but generates types at build time via a separate CLI step. Drizzle infers everything from your schema file at the TypeScript level — no codegen, no extra process, faster feedback loop.
const result = await db
.select()
.from(users)
.where(eq(users.role, 'admin'))
.limit(10);
Links:
npm install drizzle-orm — orm.drizzle.team
3. Zod — runtime validation that TypeScript actually trusts
What it is:
Schema declaration and validation library. Define a shape once, get both a TypeScript type and a runtime validator.
Why it matters:
TypeScript only protects you at compile time. The moment data comes from a form, an API, or a query string — you're on your own. Zod bridges that gap cleanly.
import { z } from 'zod';
const UserSchema = z.object({
email: z.string().email(),
age: z.number().min(18),
});
const user = UserSchema.parse(req.body); // throws if invalid
If you're building APIs in 2026 without Zod (or something like it), you're writing validation by hand and lying to yourself about it.
Links:
npm install zod — zod.dev
4. Vitest — tests that don't slow you down
What it is:
A Vite-native test runner. Jest-compatible API, but with native ESM support, instant watch mode, and built-in TypeScript support.
Why it matters:
Jest's startup time is noticeable. Vitest starts in under a second. If you're using Vite already (and you probably are), switching costs almost nothing.
import { describe, it, expect } from 'vitest';
describe('add', () => {
it('returns correct sum', () => {
expect(1 + 1).toBe(2);
});
});
Links:
npm install -D vitest — vitest.dev
5. Effect — error handling the way it should work
What it is:
A TypeScript library for writing reliable, type-safe, composable programs. Errors, async, dependencies — all tracked in the type system.
Why it matters:
try/catch doesn't tell you what can fail or why. Effect makes errors first-class citizens. Every function signature tells you exactly what it can return and what it can fail with.
import { Effect } from 'effect';
const program = Effect.tryPromise({
try: () => fetch('/api/data').then(r => r.json()),
catch: (e) => new NetworkError(String(e)),
});
Steep learning curve. Worth it for anything production-critical.
Links:
npm install effect — effect.website
6. pompelmi — antivirus scanning for Node.js that actually works
What it is:
A minimal, zero-dependency wrapper around ClamAV. Scans any file and returns a typed Verdict symbol — Verdict.Clean, Verdict.Malicious, or Verdict.ScanError.
Why it matters:
Most Node.js file upload handlers have no malware scanning at all.
The ones that do usually rely on fragile stdout parsing with regex.
pompelmi maps ClamAV exit codes directly — the stable interface — so it can't silently break between ClamAV versions.
const { scan, Verdict } = require('pompelmi');
const result = await scan(req.file.path);
if (result === Verdict.Malicious) {
return res.status(400).json({ error: 'File rejected.' });
}
No daemon needed by default. No runtime dependencies. No regex. Cross-platform.
If ClamAV runs in a container, pass host and port and the API stays identical.
pompelmi
/
pompelmi
Minimal Node.js wrapper around ClamAV — scan any file and get Clean, Malicious, or ScanError. Handles installation and database updates automatically.
pompelmi
ClamAV for humans
A minimal Node.js wrapper around ClamAV that scans any file and returns a typed Verdict Symbol: Verdict.Clean, Verdict.Malicious, or Verdict.ScanError. No daemons. No cloud. No native bindings. Zero runtime dependencies.
Table of contents
- Quickstart
- How it works
- API
- Docker / remote scanning
- Internal utilities
- Supported platforms
- Installing ClamAV manually
- Testing
- Contributing
- Security
- License
Quickstart
npm install pompelmi
const { scan, Verdict } = require('pompelmi');
const result = await scan('/path/to/file.zip');
if (result === Verdict.Malicious) {
throw new Error('File rejected: malware detected');
}
How it works
- Validate — pompelmi checks that the argument is a string and that the file exists before spawning anything.
-
Scan — pompelmi spawns
clamscan --no-summary <filePath>as a child process and reads the exit code. - Map — the exit code…
Links:
npm install pompelmi — pompelmi.app
7. ofetch — fetch that behaves like you expect
What it is:
A better fetch wrapper from the UnJS team. Auto-parses JSON, smart retries, proper error throwing, and works in Node, browsers, and edge runtimes.
Why it matters:
Native fetch is fine until you need error handling, and then you realize you have to check res.ok yourself every single time. ofetch throws on non-2xx responses by default, handles JSON automatically, and adds retry logic with a single option.
import { ofetch } from 'ofetch';
const data = await ofetch('/api/users', {
method: 'POST',
body: { name: 'Tommy' },
retry: 3,
});
Links:
npm install ofetch — github.com/unjs/ofetch
8. unstorage — one API for every storage backend
What it is:
A universal key-value storage layer. Same API whether you're writing to memory, Redis, Cloudflare KV, localStorage, the filesystem, or a database.
Why it matters:
You want to swap Redis for Cloudflare KV when you move to the edge — you shouldn't have to rewrite your caching layer. unstorage makes that a config change, not a refactor.
import { createStorage } from 'unstorage';
import redisDriver from 'unstorage/drivers/redis';
const storage = createStorage({
driver: redisDriver({ url: process.env.REDIS_URL }),
});
await storage.setItem('session:abc', { userId: 42 });
const session = await storage.getItem('session:abc');
Links:
npm install unstorage — unstorage.unjs.io
9. tsx — run TypeScript without a build step
What it is:
A CLI tool that runs .ts files directly in Node.js. Drop-in replacement for node, powered by esbuild.
Why it matters:
ts-node is slow. tsx is fast. Starts instantly, handles modern ESM TypeScript, and requires zero configuration.
npx tsx src/index.ts
# or
tsx watch src/index.ts
Replace this in your package.json:
"scripts": {
"dev": "tsx watch src/index.ts"
}
Links:
npm install -D tsx — tsx.is
10. oslo — auth primitives without the framework lock-in
What it is:
A collection of small, focused auth utilities: CSRF tokens, OTP generation, cookie handling, encoding, timing-safe comparison. From the Lucia auth team.
Why it matters:
Full auth libraries (NextAuth, Lucia) make assumptions about your framework and database. oslo gives you the low-level primitives — the pieces auth is built from — so you can compose exactly what you need.
import { generateRandomString, alphabet } from 'oslo/crypto';
import { TOTP } from 'oslo/otp';
const code = generateRandomString(8, alphabet('0-9'));
const totp = new TOTP('SHA-1', 6, 30);
const isValid = await totp.verify(userInput, secret);
Links:
npm install oslo — oslo.js.org
The list at a glance
| Package | Category | One-liner |
|---|---|---|
hono |
Framework | Edge-native, framework-agnostic web server |
drizzle-orm |
Database | Type-safe ORM, no codegen |
zod |
Validation | Schema → TypeScript type + runtime validation |
vitest |
Testing | Fast Jest-compatible test runner |
effect |
Reliability | Type-safe errors and async composition |
pompelmi |
Security | File antivirus scanning via ClamAV |
ofetch |
HTTP | fetch that handles errors and JSON automatically |
unstorage |
Storage | Universal key-value storage across backends |
tsx |
DX | Run TypeScript files instantly, no config |
oslo |
Auth | Low-level auth primitives, no framework assumptions |
Which of these are already in your stack — and which ones are you trying next?
I'm especially curious if anyone has a better alternative to effect for typed error handling without the learning curve.

Top comments (0)