DEV Community

Cover image for 10 npm packages you will use in 2026
Tommaso Bertocchi
Tommaso Bertocchi

Posted on

10 npm packages you will use in 2026

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;
Enter fullscreen mode Exit fullscreen mode

Links:
npm install honohonojs.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);
Enter fullscreen mode Exit fullscreen mode

Links:
npm install drizzle-ormorm.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
Enter fullscreen mode Exit fullscreen mode

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 zodzod.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);
  });
});
Enter fullscreen mode Exit fullscreen mode

Links:
npm install -D vitestvitest.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)),
});
Enter fullscreen mode Exit fullscreen mode

Steep learning curve. Worth it for anything production-critical.

Links:
npm install effecteffect.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.' });
}
Enter fullscreen mode Exit fullscreen mode

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.

GitHub logo pompelmi / pompelmi

Minimal Node.js wrapper around ClamAV — scan any file and get Clean, Malicious, or ScanError. Handles installation and database updates automatically.

pompelmi logo

pompelmi

ClamAV for humans

npm version license platform zero dependencies


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

npm install pompelmi
Enter fullscreen mode Exit fullscreen mode
const { scan, Verdict } = require('pompelmi');

const result = await scan('/path/to/file.zip');

if (result === Verdict.Malicious) {
  throw new Error('File rejected: malware detected');
}
Enter fullscreen mode Exit fullscreen mode

How it works

  1. Validate — pompelmi checks that the argument is a string and that the file exists before spawning anything.
  2. Scan — pompelmi spawns clamscan --no-summary <filePath> as a child process and reads the exit code.
  3. Map — the exit code…




Links:
npm install pompelmipompelmi.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,
});
Enter fullscreen mode Exit fullscreen mode

Links:
npm install ofetchgithub.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');
Enter fullscreen mode Exit fullscreen mode

Links:
npm install unstorageunstorage.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
Enter fullscreen mode Exit fullscreen mode

Replace this in your package.json:

"scripts": {
  "dev": "tsx watch src/index.ts"
}
Enter fullscreen mode Exit fullscreen mode

Links:
npm install -D tsxtsx.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);
Enter fullscreen mode Exit fullscreen mode

Links:
npm install oslooslo.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)