<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tommaso Bertocchi</title>
    <description>The latest articles on DEV Community by Tommaso Bertocchi (@sonotommy).</description>
    <link>https://dev.to/sonotommy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3399256%2F111d6919-72dc-4992-a6c6-2b20a4ccf85b.jpeg</url>
      <title>DEV Community: Tommaso Bertocchi</title>
      <link>https://dev.to/sonotommy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sonotommy"/>
    <language>en</language>
    <item>
      <title>10 npm Packages You'll Actually Use in 2026</title>
      <dc:creator>Tommaso Bertocchi</dc:creator>
      <pubDate>Wed, 22 Apr 2026 06:44:10 +0000</pubDate>
      <link>https://dev.to/sonotommy/10-npm-packages-youll-actually-use-in-2026-d64</link>
      <guid>https://dev.to/sonotommy/10-npm-packages-youll-actually-use-in-2026-d64</guid>
      <description>&lt;p&gt;Every "must-know npm packages" list links to abandoned repos or tools you already know.&lt;br&gt;
These 10 are actively maintained, TypeScript-native, and earn their spot in production code — not because they went viral.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; These 10 npm packages cut real complexity in production Node.js apps — no hype, no toy demos.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;zod&lt;/strong&gt; — runtime validation your TypeScript types can't provide&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;tsx&lt;/strong&gt; — run TypeScript instantly without a build step&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;hono&lt;/strong&gt; — the web framework fast enough for edge&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;drizzle-orm&lt;/strong&gt; — SQL-first ORM that doesn't fight TypeScript&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;superjson&lt;/strong&gt; — serialize what JSON.stringify silently mangles&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;effect&lt;/strong&gt; — structured concurrency for complex async systems&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pino&lt;/strong&gt; — the logger that won't become your bottleneck&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pompelmi&lt;/strong&gt; — file upload scanning with zero cloud dependencies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;got&lt;/strong&gt; — the HTTP client Node.js deserved from the start&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;p-queue&lt;/strong&gt; — concurrency control for async operations&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  1) zod — runtime validation your TypeScript types can't provide
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A TypeScript-first schema library that validates data at runtime, not just at compile time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters in 2026:&lt;/strong&gt; TypeScript types disappear at runtime. Zod gives you the same guarantees at the API boundary — incoming requests, form submissions, environment variables. It's become the standard because the API is clean and it composes well with frameworks like tRPC.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; API request validation, form parsing, environment variable schemas&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/colinhacks" rel="noopener noreferrer"&gt;
        colinhacks
      &lt;/a&gt; / &lt;a href="https://github.com/colinhacks/zod" rel="noopener noreferrer"&gt;
        zod
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      TypeScript-first schema validation with static type inference
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/colinhacks/zod/logo.svg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcolinhacks%2Fzod%2FHEAD%2Flogo.svg" width="200px" alt="Zod logo"&gt;&lt;/a&gt;
  &lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Zod&lt;/h1&gt;
&lt;/div&gt;
  &lt;p&gt;
    TypeScript-first schema validation with static type inference
    &lt;br&gt;
    by &lt;a href="https://x.com/colinhacks" rel="nofollow noopener noreferrer"&gt;@colinhacks&lt;/a&gt;
  &lt;/p&gt;
&lt;br&gt;
&lt;p&gt;
&lt;a href="https://github.com/colinhacks/zod/actions?query=branch%3Amain" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/colinhacks/zod/actions/workflows/test.yml/badge.svg?event=push&amp;amp;branch=main" alt="Zod CI status"&gt;&lt;/a&gt;
&lt;a href="https://opensource.org/licenses/MIT" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/802a8d5f15f827d1dad1d3cd2d83959e3a9c7a7a811b1d8a589e569e0e194600/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f636f6c696e6861636b732f7a6f64" alt="License"&gt;&lt;/a&gt;
&lt;a href="https://www.npmjs.com/package/zod" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/97874bd5076655b8fe1d1db185419304ae99932f2b1c6325bdfe06b7ba68a21a/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f64772f7a6f642e737667" alt="npm"&gt;&lt;/a&gt;
&lt;a href="https://discord.gg/KaSRdyX2vc" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9e6a3741bb85b8ac77e93363a9462b1372b78ebce714d49a43f05c76f739ec4c/68747470733a2f2f696d672e736869656c64732e696f2f646973636f72642f3839333438373832393830323431383237373f6c6162656c3d446973636f7264266c6f676f3d646973636f7264266c6f676f436f6c6f723d7768697465" alt="discord server"&gt;&lt;/a&gt;
&lt;a href="https://github.com/colinhacks/zod" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6cdf56c04f516a75e3590a182fdbbaa3b519e378fb3610127a50db5a28b56e9d/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f73746172732f636f6c696e6861636b732f7a6f64" alt="stars"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;div&gt;
  &lt;a href="https://zod.dev/api" rel="nofollow noopener noreferrer"&gt;Docs&lt;/a&gt;
  &lt;span&gt;  •  &lt;/span&gt;
  &lt;a href="https://discord.gg/RcG33DQJdf" rel="nofollow noopener noreferrer"&gt;Discord&lt;/a&gt;
  &lt;span&gt;  •  &lt;/span&gt;
  &lt;a href="https://twitter.com/colinhacks" rel="nofollow noopener noreferrer"&gt;𝕏&lt;/a&gt;
  &lt;span&gt;  •  &lt;/span&gt;
  &lt;a href="https://bsky.app/profile/zod.dev" rel="nofollow noopener noreferrer"&gt;Bluesky&lt;/a&gt;
  &lt;br&gt;
&lt;/div&gt;



&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Featured sponsor: Jazz&lt;/h2&gt;
&lt;/div&gt;

&lt;div&gt;
  &lt;a href="https://jazz.tools/?utm_source=zod" rel="nofollow noopener noreferrer"&gt;
    
      
      &lt;img alt="jazz logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fgarden-co%2Fjazz%2F938f6767e46cdfded60e50d99bf3b533f4809c68%2Fhomepage%2Fhomepage%2Fpublic%2FZod%2520sponsor%2520message.png" width="85%"&gt;
    
  &lt;/a&gt;
  &lt;br&gt;
  &lt;p&gt;Learn more about &lt;a href="mailto:sponsorship@colinhacks.com"&gt;featured sponsorships&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;



&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;&lt;a href="https://zod.dev/api" rel="nofollow noopener noreferrer"&gt;Read the docs →&lt;/a&gt;&lt;/h3&gt;

&lt;/div&gt;



&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What is Zod?&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;Zod is a TypeScript-first validation library. Define a schema and parse some data with it. You'll get back a strongly typed, validated result.&lt;/p&gt;

&lt;div class="highlight highlight-source-ts notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-k"&gt;as&lt;/span&gt; &lt;span class="pl-s1"&gt;z&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s"&gt;"zod"&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-v"&gt;User&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;z&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;object&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-c1"&gt;name&lt;/span&gt;: &lt;span class="pl-s1"&gt;z&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;string&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-c"&gt;// some untrusted data...&lt;/span&gt;
&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;input&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-c"&gt;/* stuff */&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-c"&gt;// the parsed result is validated and type safe!&lt;/span&gt;
&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;data&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-v"&gt;User&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;parse&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;input&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-c"&gt;// so you can use it with confidence :)&lt;/span&gt;
&lt;span class="pl-smi"&gt;console&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;log&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;data&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;name&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Zero external dependencies&lt;/li&gt;
&lt;li&gt;Works in Node.js and all modern browsers&lt;/li&gt;
&lt;li&gt;Tiny: &lt;code&gt;2kb&lt;/code&gt; core bundle (gzipped)&lt;/li&gt;
&lt;li&gt;Immutable API: methods…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/colinhacks/zod" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  2) tsx — run TypeScript without the setup tax
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A zero-config TypeScript runner using esbuild that executes &lt;code&gt;.ts&lt;/code&gt; files directly with &lt;code&gt;npx tsx script.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters in 2026:&lt;/strong&gt; Setting up &lt;code&gt;ts-node&lt;/code&gt; and waiting for tsc just to run a script kills momentum. tsx eliminates all of that — faster than &lt;code&gt;ts-node&lt;/code&gt;, no build step for scripts or migrations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Scripts, one-off migrations, CLI tools, prototypes&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/privatenumber/tsx" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2F1%2Fprivatenumber%2Ftsx" alt="tsx preview" width="1200" height="600"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/privatenumber" rel="noopener noreferrer"&gt;
        privatenumber
      &lt;/a&gt; / &lt;a href="https://github.com/privatenumber/tsx" rel="noopener noreferrer"&gt;
        tsx
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      ⚡️ TypeScript Execute | The easiest way to run TypeScript in Node.js
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;
&lt;br&gt;

    
    &lt;img width="160" alt="tsx" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fprivatenumber%2Ftsx%2FHEAD%2F.github%2Flogo-light.svg"&gt;

&lt;br&gt;&lt;br&gt;
&lt;a href="https://npm.im/tsx" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d037dc4ce9d376b8617b1d56a47c14db72f05c5bed4eb564e06765db861cf4a5/68747470733a2f2f62616467656e2e6e65742f6e706d2f762f747378"&gt;&lt;/a&gt; &lt;a href="https://npm.im/tsx" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6e4b2627fda12f2ad08a4b291b3afb1abe4c3b94f3fa9f563eb5577c95332a18/68747470733a2f2f62616467656e2e6e65742f6e706d2f646d2f747378"&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;
TypeScript Execute (tsx): The easiest way to run TypeScript in Node.js
&lt;br&gt;&lt;br&gt;
&lt;a href="https://tsx.is" rel="nofollow noopener noreferrer"&gt;Documentation&lt;/a&gt;    |    &lt;a href="https://tsx.is/getting-started" rel="nofollow noopener noreferrer"&gt;Getting started →&lt;/a&gt;
&lt;/p&gt;
&lt;br&gt;
&lt;p&gt;
    &lt;a href="https://github.com/sponsors/privatenumber/sponsorships?tier_id=398771" rel="noopener noreferrer"&gt;&lt;img width="412" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fprivatenumber%2Fsponsors%2Fmaster%2Fbanners%2Fassets%2Fdonate.webp"&gt;&lt;/a&gt;
    &lt;a href="https://github.com/sponsors/privatenumber/sponsorships?tier_id=416984" rel="noopener noreferrer"&gt;&lt;img width="412" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fprivatenumber%2Fsponsors%2Fmaster%2Fbanners%2Fassets%2Fsponsor.webp"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;sup&gt;&lt;i&gt;Already a sponsor?&lt;/i&gt; Join the discussion in the &lt;a href="https://github.com/pvtnbr/tsx" rel="noopener noreferrer"&gt;Development repo&lt;/a&gt;!&lt;/sup&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Sponsors&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;
    &lt;a href="https://github.com/sponsors/privatenumber" rel="noopener noreferrer"&gt;
        &lt;img src="https://camo.githubusercontent.com/cdbae141a5fb3ac0f5dea76f023add3ad6af9a8d4c5cfbf6b13ba82a169275f2/68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f707269766174656e756d6265722f73706f6e736f72732f73706f6e736f726b69742f73706f6e736f72732e737667"&gt;
    &lt;/a&gt;
&lt;/p&gt;
&lt;/div&gt;

  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/privatenumber/tsx" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  3) hono — the web framework built for the edge
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A small, fast, multi-runtime framework running on Cloudflare Workers, Deno, Bun, and Node.js with the same API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters in 2026:&lt;/strong&gt; Express was built for a different era. Hono is designed for edge deployments and V8 isolates — and it significantly outperforms Express on Node.js too. First-class TypeScript support is built in, not bolted on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Edge functions, Cloudflare Workers, REST APIs, multi-runtime services&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/honojs/hono" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2F1%2Fhonojs%2Fhono" alt="hono preview" width="1200" height="600"&gt;&lt;/a&gt; | &lt;a href="https://hono.dev" rel="noopener noreferrer"&gt;Website&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/honojs" rel="noopener noreferrer"&gt;
        honojs
      &lt;/a&gt; / &lt;a href="https://github.com/honojs/hono" rel="noopener noreferrer"&gt;
        hono
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Web framework built on Web Standards
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
  &lt;a href="https://hono.dev" rel="nofollow noopener noreferrer"&gt;
    &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fhonojs%2Fhono%2Fmain%2Fdocs%2Fimages%2Fhono-title.png" width="500" height="auto" alt="Hono"&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/honojs/hono/actions" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/56b7a314f03103b3a4a5a062f4d21c9a8168f00ff73a98a3c51d0c6007d57a6c/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f686f6e6f6a732f686f6e6f2f63692e796d6c3f6272616e63683d6d61696e" alt="GitHub Workflow Status"&gt;&lt;/a&gt;
&lt;a href="https://github.com/honojs/hono/blob/main/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/db9946e48e2cd1548d4073b68b64e9e798ea1bc35a87ea9cf381b08920cbf9dc/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f686f6e6f6a732f686f6e6f" alt="GitHub"&gt;&lt;/a&gt;
&lt;a href="https://www.npmjs.com/package/hono" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a8f40fb701d20f9daa6d24846fa340a1fab436a560f00189f3150a2ec536d927/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f686f6e6f" alt="npm"&gt;&lt;/a&gt;
&lt;a href="https://www.npmjs.com/package/hono" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4918da25fe02035177f54c460454bba621f4794cdcd0d8fedaffbaa56fc6cd8d/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f646d2f686f6e6f" alt="npm"&gt;&lt;/a&gt;
&lt;a href="https://jsr.io/@hono/hono" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/df7de5d792e00e9b2fb770213f8e419ea49bac2a41c95166c13fa56c4528818a/68747470733a2f2f6a73722e696f2f6261646765732f40686f6e6f2f686f6e6f" alt="JSR"&gt;&lt;/a&gt;
&lt;a href="https://bundlephobia.com/result?p=hono" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6542d52f5af6ec767bb564ca99cea24d3f6cef2c389dc2f2f74d66e1ba4805e2/68747470733a2f2f696d672e736869656c64732e696f2f62756e646c6570686f6269612f6d696e2f686f6e6f" alt="Bundle Size"&gt;&lt;/a&gt;
&lt;a href="https://bundlephobia.com/result?p=hono" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/64dd4b1bcc76aea500001e362673e07374dc919469e5a089e807bcb943405931/68747470733a2f2f696d672e736869656c64732e696f2f62756e646c6570686f6269612f6d696e7a69702f686f6e6f" alt="Bundle Size"&gt;&lt;/a&gt;
&lt;a href="https://github.com/honojs/hono/pulse" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/95d6a8a83a24f07666dddd8d46af5f5634335623d81ab316617832e5fea97e59/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f636f6d6d69742d61637469766974792f6d2f686f6e6f6a732f686f6e6f" alt="GitHub commit activity"&gt;&lt;/a&gt;
&lt;a href="https://github.com/honojs/hono/commits/main" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/162072b138cd2ddd4ba8d39c56a6fabf9b78df93842d5382eb83bea8ced52afe/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f686f6e6f6a732f686f6e6f" alt="GitHub last commit"&gt;&lt;/a&gt;
&lt;a href="https://codecov.io/github/honojs/hono" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ea096149ab465e6845db16cc60613e252170fea65010666b2fe0b754d252698b/68747470733a2f2f636f6465636f762e696f2f6769746875622f686f6e6f6a732f686f6e6f2f67726170682f62616467652e737667" alt="codecov"&gt;&lt;/a&gt;
&lt;a href="https://discord.gg/KMh2eNSdxV" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/17266f3b227fdbef1c0cdbec4b8e577400f02ec8aecec8783397c06a6cf27100/68747470733a2f2f696d672e736869656c64732e696f2f646973636f72642f313031313330383533393831393539373834343f6c6162656c3d446973636f7264266c6f676f3d446973636f7264" alt="Discord badge"&gt;&lt;/a&gt;
&lt;a href="https://deepwiki.com/honojs/hono" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0f5ae213ac378635adeb5d7f13cef055ad2f7d9a47b36de7b1c67dbe09f609ca/68747470733a2f2f6465657077696b692e636f6d2f62616467652e737667" alt="Ask DeepWiki"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hono - &lt;em&gt;&lt;strong&gt;means flame🔥 in Japanese&lt;/strong&gt;&lt;/em&gt; - is a small, simple, and ultrafast web framework built on Web Standards. It works on any JavaScript runtime: Cloudflare Workers, Fastly Compute, Deno, Bun, Vercel, AWS Lambda, Lambda@Edge, and Node.js.&lt;/p&gt;
&lt;p&gt;Fast, but not only fast.&lt;/p&gt;
&lt;div class="highlight highlight-source-ts notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-v"&gt;Hono&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s"&gt;'hono'&lt;/span&gt;
&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;app&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-v"&gt;Hono&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
&lt;span class="pl-s1"&gt;app&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;get&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'/'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;c&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-c1"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pl-s1"&gt;c&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;text&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'Hono!'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;

&lt;span class="pl-k"&gt;export&lt;/span&gt; &lt;span class="pl-k"&gt;default&lt;/span&gt; &lt;span class="pl-s1"&gt;app&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quick Start&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm create hono@latest&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ultrafast&lt;/strong&gt; 🚀 - The router &lt;code&gt;RegExpRouter&lt;/code&gt; is really fast. Not using linear loops. Fast.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lightweight&lt;/strong&gt; 🪶 - The &lt;code&gt;hono/tiny&lt;/code&gt; preset is under 12kB. Hono has zero dependencies and uses only the Web Standard API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-runtime&lt;/strong&gt; 🌍 - Works on Cloudflare Workers, Fastly Compute, Deno, Bun, AWS Lambda, Lambda@Edge, or Node.js. The same code runs on all platforms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batteries Included&lt;/strong&gt; 🔋 - Hono has built-in middleware, custom middleware, and third-party…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/honojs/hono" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpqkxff3rxx9tsl2utxqe.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpqkxff3rxx9tsl2utxqe.gif" alt="developer realizing their framework runs everywhere" width="360" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;When your web framework runs on Node.js, Bun, Deno, and the edge. Source: &lt;a href="https://giphy.com/gifs/3oKIPnAiaMCws8nOsE" rel="noopener noreferrer"&gt;Giphy&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  4) drizzle-orm — the ORM that doesn't hide SQL from you
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A TypeScript ORM with a SQL-like query API that generates type-safe queries without abstracting the database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters in 2026:&lt;/strong&gt; ORMs that hide SQL work until queries get complex. Drizzle stays close to SQL, generates types from your schema, and runs cleanly in serverless environments where Prisma's connection model struggles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; PostgreSQL, MySQL, SQLite, apps with complex queries, serverless environments&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/drizzle-team/drizzle-orm" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2F1%2Fdrizzle-team%2Fdrizzle-orm" alt="drizzle-orm preview" width="1200" height="600"&gt;&lt;/a&gt; | &lt;a href="https://orm.drizzle.team" rel="noopener noreferrer"&gt;Website&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/drizzle-team" rel="noopener noreferrer"&gt;
        drizzle-team
      &lt;/a&gt; / &lt;a href="https://github.com/drizzle-team/drizzle-orm" rel="noopener noreferrer"&gt;
        drizzle-orm
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      ORM
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/drizzle-team/drizzle-orm/./misc/readme/logo-github-sq-dark.svg#gh-dark-mode-only"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fdrizzle-team%2Fdrizzle-orm%2FHEAD%2F.%2Fmisc%2Freadme%2Flogo-github-sq-dark.svg%23gh-dark-mode-only"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/drizzle-team/drizzle-orm/./misc/readme/logo-github-sq-light.svg#gh-light-mode-only"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fdrizzle-team%2Fdrizzle-orm%2FHEAD%2F.%2Fmisc%2Freadme%2Flogo-github-sq-light.svg%23gh-light-mode-only"&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;div&gt;
  &lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Headless ORM for NodeJS, TypeScript and JavaScript 🚀&lt;/h3&gt;
&lt;/div&gt;
  &lt;a href="https://orm.drizzle.team" rel="nofollow noopener noreferrer"&gt;Website&lt;/a&gt; •
  &lt;a href="https://orm.drizzle.team/docs/overview" rel="nofollow noopener noreferrer"&gt;Documentation&lt;/a&gt; •
  &lt;a href="https://x.com/drizzleorm" rel="nofollow noopener noreferrer"&gt;Twitter&lt;/a&gt; •
  &lt;a href="https://driz.link/discord" rel="nofollow noopener noreferrer"&gt;Discord&lt;/a&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;What's Drizzle?&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;Drizzle is a modern TypeScript ORM developers &lt;a href="https://stateofdb.com/tools/drizzle" rel="nofollow noopener noreferrer"&gt;wanna use in their next project&lt;/a&gt;
It is &lt;a href="https://bundlephobia.com/package/drizzle-orm" rel="nofollow noopener noreferrer"&gt;lightweight&lt;/a&gt; at only ~7.4kb minified+gzipped, and it's tree shakeable with exactly 0 dependencies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Drizzle supports every PostgreSQL, MySQL and SQLite database&lt;/strong&gt;, including serverless ones like &lt;a href="https://orm.drizzle.team/docs/get-started-sqlite#turso" rel="nofollow noopener noreferrer"&gt;Turso&lt;/a&gt;, &lt;a href="https://orm.drizzle.team/docs/get-started-postgresql#neon" rel="nofollow noopener noreferrer"&gt;Neon&lt;/a&gt;, &lt;a href="https://orm.drizzle.team/docs/connect-xata" rel="nofollow noopener noreferrer"&gt;Xata&lt;/a&gt;, &lt;a href="https://orm.drizzle.team/docs/get-started-mysql#planetscale" rel="nofollow noopener noreferrer"&gt;PlanetScale&lt;/a&gt;, &lt;a href="https://orm.drizzle.team/docs/get-started-sqlite#cloudflare-d1" rel="nofollow noopener noreferrer"&gt;Cloudflare D1&lt;/a&gt;, &lt;a href="https://fly.io/docs/litefs/" rel="nofollow noopener noreferrer"&gt;FlyIO LiteFS&lt;/a&gt;, &lt;a href="https://orm.drizzle.team/docs/get-started-postgresql#vercel-postgres" rel="nofollow noopener noreferrer"&gt;Vercel Postgres&lt;/a&gt;, &lt;a href="https://orm.drizzle.team/docs/get-started-postgresql#supabase" rel="nofollow noopener noreferrer"&gt;Supabase&lt;/a&gt; and &lt;a href="https://orm.drizzle.team/docs/get-started-postgresql#aws-data-api" rel="nofollow noopener noreferrer"&gt;AWS Data API&lt;/a&gt;. No bells and whistles, no Rust binaries, no serverless adapters, everything just works out of the box.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Drizzle is serverless-ready by design&lt;/strong&gt;. It works in every major JavaScript runtime like NodeJS, Bun, Deno, Cloudflare Workers, Supabase functions, any Edge runtime, and even in browsers.&lt;br&gt;
With Drizzle you can be &lt;a href="https://orm.drizzle.team/benchmarks" rel="nofollow noopener noreferrer"&gt;&lt;strong&gt;fast out of the box&lt;/strong&gt;&lt;/a&gt; and save time and costs while never introducing any data proxies into your…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/drizzle-team/drizzle-orm" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  5) superjson — serialize what JSON.stringify silently mangles
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A drop-in JSON replacement that handles &lt;code&gt;Date&lt;/code&gt;, &lt;code&gt;Map&lt;/code&gt;, &lt;code&gt;Set&lt;/code&gt;, &lt;code&gt;BigInt&lt;/code&gt;, and &lt;code&gt;undefined&lt;/code&gt; without silent type coercion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters in 2026:&lt;/strong&gt; Every full-stack app gets burned by &lt;code&gt;JSON.stringify&lt;/code&gt; turning &lt;code&gt;Date&lt;/code&gt; objects into strings or dropping &lt;code&gt;undefined&lt;/code&gt; silently. Superjson extends JSON with type metadata — predictable serialization across every server/client boundary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; tRPC, Next.js, full-stack apps with complex data types&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/blitz-js/superjson" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2F1%2Fblitz-js%2Fsuperjson" alt="superjson preview" width="1200" height="600"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/flightcontrolhq" rel="noopener noreferrer"&gt;
        flightcontrolhq
      &lt;/a&gt; / &lt;a href="https://github.com/flightcontrolhq/superjson" rel="noopener noreferrer"&gt;
        superjson
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Safely serialize JavaScript expressions to a superset of JSON, which includes Dates, BigInts, and more.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/flightcontrolhq/superjson/./docs/superjson-banner.png"&gt;&lt;img alt="superjson" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fflightcontrolhq%2Fsuperjson%2FHEAD%2F.%2Fdocs%2Fsuperjson-banner.png" width="800"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
  Safely serialize JavaScript expressions to a superset of JSON, which includes Dates, BigInts, and more
&lt;/p&gt;
&lt;p&gt;
&lt;a href="https://github.com/flightcontrolhq/superjson#contributors" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a4c14f95e6b5648025059709113992d276df6870b96d088f78a2ebe14a8aedc2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f616c6c5f636f6e7472696275746f72732d33312d6f72616e67652e7376673f7374796c653d666c61742d737175617265" alt="All Contributors"&gt;&lt;/a&gt;
  &lt;a href="https://www.npmjs.com/package/superjson" rel="nofollow noopener noreferrer"&gt;
    &lt;img alt="npm" src="https://camo.githubusercontent.com/ecbbf188e24e656005ab5470b89b40bf8e03e95ef5c002cc16735cff544a6620/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f73757065726a736f6e"&gt;
  &lt;/a&gt;
  &lt;a href="https://lgtm.com/projects/g/blitz-js/superjson/context:javascript" rel="nofollow noopener noreferrer"&gt;
    &lt;img alt="Language grade: JavaScript" src="https://camo.githubusercontent.com/bbefe7354fce8c26da890bd67ef3d826b27d006ea31a9009d1f05b5cb57fd133/68747470733a2f2f696d672e736869656c64732e696f2f6c67746d2f67726164652f6a6176617363726970742f672f626c69747a2d6a732f73757065726a736f6e2e7376673f6c6f676f3d6c67746d266c6f676f57696474683d3138"&gt;
  &lt;/a&gt;
  &lt;a href="https://github.com/blitz-js/superjson/actions" rel="noopener noreferrer"&gt;
    &lt;img alt="CI" src="https://github.com/blitz-js/superjson/workflows/CI/badge.svg"&gt;
  &lt;/a&gt;
&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Key features&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;🍱 Reliable serialization and deserialization&lt;/li&gt;
&lt;li&gt;🔐 Type safety with autocompletion&lt;/li&gt;
&lt;li&gt;🐾 Negligible runtime footprint&lt;/li&gt;
&lt;li&gt;💫 Framework agnostic&lt;/li&gt;
&lt;li&gt;🛠 Perfect fix for Next.js's serialisation limitations in &lt;code&gt;getServerSideProps&lt;/code&gt; and &lt;code&gt;getInitialProps&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Backstory&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;At &lt;a href="https://github.com/blitz-js/blitz" rel="noopener noreferrer"&gt;Blitz&lt;/a&gt;, we have struggled with the limitations of JSON. We often find ourselves working with &lt;code&gt;Date&lt;/code&gt;, &lt;code&gt;Map&lt;/code&gt;, &lt;code&gt;Set&lt;/code&gt; or &lt;code&gt;BigInt&lt;/code&gt;, but &lt;code&gt;JSON.stringify&lt;/code&gt; doesn't support any of them without going through the hassle of converting manually!&lt;/p&gt;

&lt;p&gt;Superjson solves these issues by providing a thin wrapper over &lt;code&gt;JSON.stringify&lt;/code&gt; and &lt;code&gt;JSON.parse&lt;/code&gt;.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Sponsors&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://www.flightcontrol.dev/?ref=superjson" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fblitz-js%2Fblitz%2Fmain%2Fassets%2Fflightcontrol.png" alt="Flightcontrol Logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Superjson logo by &lt;a href="https://github.com/numi-hq/open-design" rel="noopener noreferrer"&gt;NUMI&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://numi.tech/?ref=superjson" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnumi-hq%2Fopen-design%2Fmain%2Fassets%2Fnumi-lockup.png" alt="NUMI Logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting started&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;Install the library with your package manager of choice, e.g.:&lt;/p&gt;

&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;yarn add superjson
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Basic Usage&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;The easiest way to use Superjson is with its &lt;code&gt;stringify&lt;/code&gt; and &lt;code&gt;parse&lt;/code&gt; functions. If you know how to use &lt;code&gt;JSON.stringify&lt;/code&gt;, you already know Superjson!&lt;/p&gt;

&lt;p&gt;Easily stringify…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/flightcontrolhq/superjson" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;





&lt;h2&gt;
  
  
  6) effect — structured concurrency for when async/await breaks down
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A TypeScript library for reliable applications using typed effects, structured concurrency, and composable error handling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters in 2026:&lt;/strong&gt; Retries, timeouts, cancellation, and dependency injection all become ad hoc bolted-on solutions with &lt;code&gt;async/await&lt;/code&gt;. Effect provides a principled model for these problems. The learning curve is real and the payoff matches it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Complex backend services, data pipelines, apps with sophisticated retry/timeout/cancellation needs&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/Effect-TS/effect" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2F1%2FEffect-TS%2Feffect" alt="effect preview" width="1200" height="600"&gt;&lt;/a&gt; | &lt;a href="https://effect.website" rel="noopener noreferrer"&gt;Website&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Effect-TS" rel="noopener noreferrer"&gt;
        Effect-TS
      &lt;/a&gt; / &lt;a href="https://github.com/Effect-TS/effect" rel="noopener noreferrer"&gt;
        effect
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Build production-ready applications in TypeScript
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/a485f9eb96f211d24ce024dd93d08537d11e46dc21bfe38dda58f8e82c2abe83/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f656666656374"&gt;&lt;img src="https://camo.githubusercontent.com/a485f9eb96f211d24ce024dd93d08537d11e46dc21bfe38dda58f8e82c2abe83/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f656666656374" alt="npm version"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Effect Monorepo&lt;/h1&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;An ecosystem of tools to build robust applications in TypeScript&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Introduction&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Welcome to Effect, a powerful TypeScript framework that provides a fully-fledged functional effect system with a rich standard library.&lt;/p&gt;
&lt;p&gt;Effect consists of several packages that work together to help build robust TypeScript applications. The core package, &lt;code&gt;effect&lt;/code&gt;, serves as the foundation of the framework, offering primitives for managing side effects, ensuring type safety, and supporting concurrency.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Monorepo Structure&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;The Effect monorepo is organized into multiple packages, each extending the core functionality. Below is an overview of the packages included:&lt;/p&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;

&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;effect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Core package&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/Effect-TS/effect/blob/main/packages/effect/README.md" rel="noopener noreferrer"&gt;README&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@effect/ai&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;AI utilities&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/Effect-TS/effect/blob/main/packages/ai/ai/README.md" rel="noopener noreferrer"&gt;README&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@effect/ai-openai&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;OpenAI utilities&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/Effect-TS/effect/blob/main/packages/ai/openai/README.md" rel="noopener noreferrer"&gt;README&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@effect/ai-anthropic&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Anthropic utilities&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/Effect-TS/effect/blob/main/packages/ai/anthropic/README.md" rel="noopener noreferrer"&gt;README&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@effect/ai-amazon-bedrock&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Effect modules for working with Amazon Bedrock AI apis&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/Effect-TS/effect/blob/main/packages/ai/amazon-bedrock/README.md" rel="noopener noreferrer"&gt;README&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@effect/ai-google&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Effect modules for working with Google AI apis&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/Effect-TS/effect/blob/main/packages/ai/google/README.md" rel="noopener noreferrer"&gt;README&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@effect/cli&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CLI utilities&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/Effect-TS/effect/blob/main/packages/cli/README.md" rel="noopener noreferrer"&gt;README&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@effect/cluster&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Distributed computing tools&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/Effect-TS/effect/blob/main/packages/cluster/README.md" rel="noopener noreferrer"&gt;README&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@effect/experimental&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Experimental features and APIs&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/Effect-TS/effect/blob/main/packages/experimental/README.md" rel="noopener noreferrer"&gt;README&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@effect/opentelemetry&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://opentelemetry.io/" rel="nofollow noopener noreferrer"&gt;OpenTelemetry&lt;/a&gt; integration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Effect-TS/effect" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  7) pino — the logger that won't slow your server down
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; An extremely fast, JSON-native Node.js logger that uses worker threads for async serialization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters in 2026:&lt;/strong&gt; Synchronous logging blocks the event loop — at high request rates it becomes a measurable bottleneck. Pino moves serialization off the main thread, giving you structured JSON output compatible with Loki/Datadog/CloudWatch at negligible latency cost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Production Node.js services, high-traffic APIs, apps sending logs to aggregation systems&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/pinojs/pino" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2F1%2Fpinojs%2Fpino" alt="pino preview" width="1200" height="600"&gt;&lt;/a&gt; | &lt;a href="https://getpino.io" rel="noopener noreferrer"&gt;Website&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/pinojs" rel="noopener noreferrer"&gt;
        pinojs
      &lt;/a&gt; / &lt;a href="https://github.com/pinojs/pino" rel="noopener noreferrer"&gt;
        pino
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      🌲 super fast, all natural json logger
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/pinojs/pino/pino-banner.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fpinojs%2Fpino%2FHEAD%2Fpino-banner.png" alt="banner"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;pino&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://www.npmjs.com/package/pino" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a823df3cec814cc335378f313ae9a9509336601bd21787f8417ad63dfc161098/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f70696e6f" alt="npm version"&gt;&lt;/a&gt;
&lt;a href="https://github.com/pinojs/pino/actions" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/35ba93946da80d315675aec51319e3390a256f57eb2b168361618c639e3d8e1e/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f70696e6f6a732f70696e6f2f63692e796d6c" alt="Build Status"&gt;&lt;/a&gt;
&lt;a href="https://standardjs.com/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7b0cf28a45897496a5a422fdedbf2123cc96b204e01fc53a5fca9bc2842592a3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f64652532307374796c652d7374616e646172642d627269676874677265656e2e7376673f7374796c653d666c6174" alt="js-standard-style"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/pinojs/pino#low-overhead" rel="noopener noreferrer"&gt;Very low overhead&lt;/a&gt; JavaScript logger.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Documentation&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/docs/benchmarks.md" rel="noopener noreferrer"&gt;Benchmarks ⇗&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/docs/api.md" rel="noopener noreferrer"&gt;API ⇗&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/docs/browser.md" rel="noopener noreferrer"&gt;Browser API ⇗&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/docs/redaction.md" rel="noopener noreferrer"&gt;Redaction ⇗&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/docs/child-loggers.md" rel="noopener noreferrer"&gt;Child Loggers ⇗&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/docs/transports.md" rel="noopener noreferrer"&gt;Transports ⇗&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/docs/diagnostics.md" rel="noopener noreferrer"&gt;Diagnostics ⇗&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/docs/web.md" rel="noopener noreferrer"&gt;Web Frameworks ⇗&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/docs/pretty.md" rel="noopener noreferrer"&gt;Pretty Printing ⇗&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/docs/asynchronous.md" rel="noopener noreferrer"&gt;Asynchronous Logging ⇗&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/docs/ecosystem.md" rel="noopener noreferrer"&gt;Ecosystem ⇗&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/docs/help.md" rel="noopener noreferrer"&gt;Help ⇗&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/docs/lts.md" rel="noopener noreferrer"&gt;Long Term Support Policy ⇗&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Runtimes&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Node.js&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Pino is built to run on &lt;a href="http://nodejs.org" rel="nofollow noopener noreferrer"&gt;Node.js&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Bare&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Pino works on &lt;a href="https://github.com/holepunchto/bare" rel="noopener noreferrer"&gt;Bare&lt;/a&gt; with the &lt;a href="https://github.com/pinojs/pino-bare" rel="noopener noreferrer"&gt;&lt;code&gt;pino-bare&lt;/code&gt;&lt;/a&gt; compatability module.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Pear&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Pino works on &lt;a href="https://docs.pears.com" rel="nofollow noopener noreferrer"&gt;Pear&lt;/a&gt;, which is built on &lt;a href="https://github.com/holepunchto/bare" rel="noopener noreferrer"&gt;Bare&lt;/a&gt;, with the &lt;a href="https://github.com/pinojs/pino-bare" rel="noopener noreferrer"&gt;&lt;code&gt;pino-bare&lt;/code&gt;&lt;/a&gt; compatibility module.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Install&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Using NPM:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;$ npm install pino
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Using YARN:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;$ yarn add pino
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you would like to install pino v6, refer to &lt;a href="https://github.com/pinojs/pino/tree/v6.x" rel="noopener noreferrer"&gt;https://github.com/pinojs/pino/tree/v6.x&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-js notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;logger&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;require&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'pino'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;

&lt;span class="pl-s1"&gt;logger&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;info&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'hello world'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;

&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;child&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;logger&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;child&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-c1"&gt;a&lt;/span&gt;: &lt;span class="pl-s"&gt;'property'&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
&lt;span class="pl-s1"&gt;child&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;info&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'hello child!'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;This produces:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;{"level":30,"time":1531171074631,"msg":"hello world","pid":657,"hostname":"Davids-MBP-3.fritz.box"}
{"level":30,"time":1531171082399,"msg":"hello child!","pid":657,"hostname":"Davids-MBP-3.fritz.box","a":"property"}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For using Pino with…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/pinojs/pino" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3hcvc1mhqf3kz258vrvu.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3hcvc1mhqf3kz258vrvu.gif" alt="developer watching logs in production" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Watching your synchronous logger block the event loop at 10k req/s. Source: &lt;a href="https://giphy.com/gifs/5nvQ7fBWhPVXXOcfRI" rel="noopener noreferrer"&gt;Giphy&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  8) pompelmi — file upload scanning that stays on your server
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A minimal Node.js wrapper around ClamAV that scans any uploaded file and returns a typed verdict — Clean, Malicious, or ScanError. Zero runtime dependencies, no cloud, no daemon required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters in 2026:&lt;/strong&gt; File uploads are one of the most consistently overlooked attack surfaces in web applications. Most teams skip scanning or bolt on an expensive third-party API. pompelmi solves this locally — no data leaving your server, no subscription fee.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Express, Fastify, NestJS, Next.js, SvelteKit, any Node.js app that accepts user file uploads&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/pompelmi/pompelmi" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2F1%2Fpompelmi%2Fpompelmi" alt="pompelmi preview" width="800" height="400"&gt;&lt;/a&gt; | &lt;a href="https://pompelmi.app" rel="noopener noreferrer"&gt;Website&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/pompelmi" rel="noopener noreferrer"&gt;
        pompelmi
      &lt;/a&gt; / &lt;a href="https://github.com/pompelmi/pompelmi" rel="noopener noreferrer"&gt;
        pompelmi
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Minimal Node.js wrapper around ClamAV — scan any file and get Clean, Malicious, or ScanError. Handles installation and database updates automatically.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/pompelmi/pompelmi/./src/grapefruit.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fpompelmi%2Fpompelmi%2FHEAD%2F.%2Fsrc%2Fgrapefruit.png" width="96" alt="pompelmi logo"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;pompelmi&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;ClamAV for humans&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://www.npmjs.com/package/pompelmi" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/afa9095da8c286a9d2f798ae9d02cfcf6db0ae0efc625cdf7ee757b8af5e9924/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f706f6d70656c6d692e737667" alt="npm version"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/95c61c397ca3825757ec835268e50886b2c10ddc4f0676e1222b19037610927f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4953432d626c75652e737667"&gt;&lt;img src="https://camo.githubusercontent.com/95c61c397ca3825757ec835268e50886b2c10ddc4f0676e1222b19037610927f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4953432d626c75652e737667" alt="license"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/489444e15856929c362ce966520a248149a338daec3ec32dec3f83554d46caca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f706c6174666f726d2d6d61634f532532302537432532304c696e757825323025374325323057696e646f77732d6c69676874677265792e737667"&gt;&lt;img src="https://camo.githubusercontent.com/489444e15856929c362ce966520a248149a338daec3ec32dec3f83554d46caca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f706c6174666f726d2d6d61634f532532302537432532304c696e757825323025374325323057696e646f77732d6c69676874677265792e737667" alt="platform"&gt;&lt;/a&gt;
  &lt;a href="https://www.npmjs.com/package/pompelmi?activeTab=dependencies" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/aae95fbaa83bc6a3f4597f3a75da45ea46ec236fc324617f0e5a2f15e07fe750/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646570656e64656e636965732d302d627269676874677265656e" alt="zero dependencies"&gt;&lt;/a&gt;
&lt;/p&gt;




&lt;p&gt;A minimal Node.js wrapper around &lt;a href="https://www.clamav.net/" rel="nofollow noopener noreferrer"&gt;ClamAV&lt;/a&gt; that scans any file and returns a typed &lt;code&gt;Verdict&lt;/code&gt; Symbol: &lt;code&gt;Verdict.Clean&lt;/code&gt;, &lt;code&gt;Verdict.Malicious&lt;/code&gt;, or &lt;code&gt;Verdict.ScanError&lt;/code&gt;. No daemons. No cloud. No native bindings. Zero runtime dependencies.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Table of contents&lt;/h2&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#quickstart" rel="noopener noreferrer"&gt;Quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#how-it-works" rel="noopener noreferrer"&gt;How it works&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/pompelmi/pompelmi#api" rel="noopener noreferrer"&gt;API&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#pompelmiscanfilepath-options" rel="noopener noreferrer"&gt;pompelmi.scan()&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#docker--remote-scanning" rel="noopener noreferrer"&gt;Docker / remote scanning&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#examples" rel="noopener noreferrer"&gt;Examples&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/pompelmi/pompelmi#internal-utilities" rel="noopener noreferrer"&gt;Internal utilities&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#clamavinstaller" rel="noopener noreferrer"&gt;ClamAVInstaller()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#updateclamavdatabase" rel="noopener noreferrer"&gt;updateClamAVDatabase()&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#supported-platforms" rel="noopener noreferrer"&gt;Supported platforms&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#installing-clamav-manually" rel="noopener noreferrer"&gt;Installing ClamAV manually&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#testing" rel="noopener noreferrer"&gt;Testing&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#contributing" rel="noopener noreferrer"&gt;Contributing&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#security" rel="noopener noreferrer"&gt;Security&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;
&lt;br&gt;


&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quickstart&lt;/h2&gt;
&lt;/div&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install pompelmi&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight highlight-source-js notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; scan&lt;span class="pl-kos"&gt;,&lt;/span&gt; Verdict &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;require&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'pompelmi'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;result&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;await&lt;/span&gt; &lt;span class="pl-en"&gt;scan&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'/path/to/file.zip'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-k"&gt;if&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;result&lt;/span&gt; &lt;span class="pl-c1"&gt;===&lt;/span&gt; &lt;span class="pl-v"&gt;Verdict&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;Malicious&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-k"&gt;throw&lt;/span&gt; &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-v"&gt;Error&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'File rejected: malware detected'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How it works&lt;/h2&gt;

&lt;/div&gt;


&lt;ol&gt;

&lt;li&gt;

&lt;strong&gt;Validate&lt;/strong&gt; — pompelmi checks that the argument is a string and that the file exists before spawning anything.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Scan&lt;/strong&gt; — pompelmi spawns &lt;code&gt;clamscan --no-summary &amp;lt;filePath&amp;gt;&lt;/code&gt; as a child process and reads the exit code.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Map&lt;/strong&gt; — the exit…&lt;/li&gt;

&lt;/ol&gt;
&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/pompelmi/pompelmi" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;





&lt;h2&gt;
  
  
  9) got — the HTTP client Node.js always needed
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A feature-rich HTTP client for Node.js with hooks, retries, pagination, and streams built in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters in 2026:&lt;/strong&gt; Built-in &lt;code&gt;fetch&lt;/code&gt; is fine for simple requests. Got is for production HTTP — configurable retries, timeout handling, automatic JSON parsing, caching plugins. It handles the edge cases that matter under real outbound traffic loads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; API clients, web scrapers, microservice communication, significant outbound HTTP workloads&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/sindresorhus/got" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2F1%2Fsindresorhus%2Fgot" alt="got preview" width="1200" height="600"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/sindresorhus" rel="noopener noreferrer"&gt;
        sindresorhus
      &lt;/a&gt; / &lt;a href="https://github.com/sindresorhus/got" rel="noopener noreferrer"&gt;
        got
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      🌐 Human-friendly and powerful HTTP request library for Node.js
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;a rel="noopener noreferrer" href="https://github.com/sindresorhus/got/media/logo.svg"&gt;&lt;img width="360" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fsindresorhus%2Fgot%2FHEAD%2Fmedia%2Flogo.svg" alt="Got"&gt;&lt;/a&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    
    
&lt;p&gt;
            &lt;sup&gt;
                Sindre's open source work is supported by the community.&lt;br&gt;Special thanks to
            &lt;/sup&gt;
        &lt;/p&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;a href="https://www.fame.fi#gh-light-mode-only" rel="nofollow noopener noreferrer"&gt;
            &lt;img src="https://camo.githubusercontent.com/530e38a7caeab62ae80ce5023709b94b8a21b7171b3b1ebf0eb8e383a6c8ce06/68747470733a2f2f73696e647265736f726875732e636f6d2f6173736574732f7468616e6b732f66616d652d6c6f676f2d6c696768742e737667" width="200" alt="Fame Helsinki"&gt;
        &lt;/a&gt;
        &lt;a href="https://www.fame.fi#gh-dark-mode-only" rel="nofollow noopener noreferrer"&gt;
            &lt;img src="https://camo.githubusercontent.com/0a5384dc3674f4dc52b0ef9d83caa40b5554e203d9b10c9644d184819f947d0c/68747470733a2f2f73696e647265736f726875732e636f6d2f6173736574732f7468616e6b732f66616d652d6c6f676f2d6461726b2e737667" width="200" alt="Fame Helsinki"&gt;
        &lt;/a&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;a href="https://depot.dev?utm_source=github&amp;amp;utm_medium=sindresorhus" rel="nofollow noopener noreferrer"&gt;
            &lt;div&gt;
                
                    
                    
                    &lt;img width="180" src="https://camo.githubusercontent.com/ab8813a90486b6a95520d3d2d7516eaeadac9fa75678b60f7d497140e4d5eba3/68747470733a2f2f73696e647265736f726875732e636f6d2f6173736574732f7468616e6b732f6465706f742d6c6f676f2d6c696768742e737667" alt="Depot logo"&gt;
                
            &lt;/div&gt;
            &lt;b&gt;Fast remote container builds and GitHub Actions runners.&lt;/b&gt;
        &lt;/a&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;br&gt;
    
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
    &lt;br&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Human-friendly and powerful HTTP request library for Node.js&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://npmjs.com/got" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/74af4af3816fa55f69762e1fb3764d7ea2c7618cda842b21235b00aa2c76ef7d/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f646d2f676f742e737667" alt="Downloads"&gt;&lt;/a&gt;
&lt;a href="https://packagephobia.com/result?p=got" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/58a14825cc0941aee0f10c9e03d22736239362e705bd47b5128db35d86a854c7/68747470733a2f2f7061636b61676570686f6269612e636f6d2f62616467653f703d676f74" alt="Install size"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/sindresorhus/got#comparison" rel="noopener noreferrer"&gt;See how Got compares to other HTTP libraries&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You probably want &lt;a href="https://github.com/sindresorhus/ky" rel="noopener noreferrer"&gt;Ky&lt;/a&gt; instead, by the same people. It's smaller, works in the browser too, and is more stable since it's built on &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;Fetch&lt;/code&gt;&lt;/a&gt;. Or &lt;a href="https://github.com/sindresorhus/fetch-extras" rel="noopener noreferrer"&gt;fetch-extras&lt;/a&gt; for simple needs.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Support questions should be asked &lt;a href="https://github.com/sindresorhus/got/discussions" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Install&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install got&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; This package is native &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules" rel="nofollow noopener noreferrer"&gt;ESM&lt;/a&gt; and no longer provides a CommonJS export. If your project uses CommonJS, you will have to &lt;a href="https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c" rel="noopener noreferrer"&gt;convert to ESM&lt;/a&gt;. Please don't open issues for questions regarding CommonJS / ESM.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Got v11 is no longer maintained and we will not accept any backport requests.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Take a peek&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;A &lt;a href="https://github.com/sindresorhus/got/documentation/quick-start.md" rel="noopener noreferrer"&gt;quick start&lt;/a&gt; guide is available.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;JSON mode&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Got has a dedicated option for handling JSON payload.&lt;br&gt;
Furthermore, the…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/sindresorhus/got" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  10) p-queue — concurrency control for async operations
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A promise queue with configurable concurrency, priority support, and rate limiting for throttling async workloads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters in 2026:&lt;/strong&gt; Unconstrained parallelism causes incidents. Fire 500 database queries at once with &lt;code&gt;Promise.all&lt;/code&gt; and you'll saturate your connection pool fast. p-queue gives you exact concurrency control with priority ordering and interval-based rate limiting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Bulk API calls, image processing pipelines, database batch operations, any async workload needing throttling&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/sindresorhus/p-queue" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2F1%2Fsindresorhus%2Fp-queue" alt="p-queue preview" width="1200" height="600"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/sindresorhus" rel="noopener noreferrer"&gt;
        sindresorhus
      &lt;/a&gt; / &lt;a href="https://github.com/sindresorhus/p-queue" rel="noopener noreferrer"&gt;
        p-queue
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Promise queue with concurrency control
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;p-queue&lt;/h1&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Promise queue with concurrency control&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Useful for rate-limiting async (or sync) operations. For example, when interacting with a REST API or when doing CPU/memory intensive tasks.&lt;/p&gt;
&lt;p&gt;For servers, you probably want a Redis-backed &lt;a href="https://github.com/sindresorhus/awesome-nodejs#job-queues" rel="noopener noreferrer"&gt;job queue&lt;/a&gt; instead.&lt;/p&gt;
&lt;p&gt;Note that the project is feature complete. We are happy to review pull requests, but we don't plan any further development. We are also not answering email support questions.&lt;/p&gt;

&lt;br&gt;
&lt;div&gt;
    
&lt;p&gt;
            &lt;sup&gt;
                &lt;a href="https://github.com/sponsors/sindresorhus" rel="noopener noreferrer"&gt;Sindre's open source work is supported by the community&lt;/a&gt;&lt;br&gt;Special thanks to
            &lt;/sup&gt;
        &lt;/p&gt;
        &lt;br&gt;
        &lt;br&gt;
        &lt;a href="https://fetchfox.ai?ref=sindre" rel="nofollow noopener noreferrer"&gt;
            &lt;div&gt;
                &lt;img src="https://camo.githubusercontent.com/b8de3fd9dcd0c15843299bd4ac445d9fd18b268f339bc907b9b068a0d9f9616e/68747470733a2f2f73696e647265736f726875732e636f6d2f6173736574732f7468616e6b732f6665746368666f782d6c6f676f2e737667" height="200"&gt;
            &lt;/div&gt;
            &lt;b&gt;Scrape anything with FetchFox&lt;/b&gt;
            &lt;div&gt;
                &lt;sup&gt;FetchFox is an AI powered scraping tool that lets you scrape data from any website&lt;/sup&gt;
            &lt;/div&gt;
        &lt;/a&gt;
    &lt;br&gt;
    &lt;br&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Install&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install p-queue&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; This package is native &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules" rel="nofollow noopener noreferrer"&gt;ESM&lt;/a&gt; and no longer provides a CommonJS export. If your project uses CommonJS, you'll have to &lt;a href="https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c" rel="noopener noreferrer"&gt;convert to ESM&lt;/a&gt;. Please don't open issues for questions regarding CommonJS / ESM.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Here we run only one promise at a time. For example, set &lt;code&gt;concurrency&lt;/code&gt;…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/sindresorhus/p-queue" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;These 10 packages are fast, typed, and solve problems you only recognize from production experience. Which ones are already in your stack?&lt;/p&gt;

</description>
      <category>node</category>
      <category>npm</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Pompelmi — Add Antivirus Scanning to Your Node.js App in 5 Minutes</title>
      <dc:creator>Tommaso Bertocchi</dc:creator>
      <pubDate>Tue, 21 Apr 2026 15:23:16 +0000</pubDate>
      <link>https://dev.to/sonotommy/pompelmi-add-antivirus-scanning-to-your-nodejs-app-in-5-minutes-2eba</link>
      <guid>https://dev.to/sonotommy/pompelmi-add-antivirus-scanning-to-your-nodejs-app-in-5-minutes-2eba</guid>
      <description>&lt;h2&gt;
  
  
  Pompelmi — Add Antivirus Scanning to Your Node.js App in 5 Minutes
&lt;/h2&gt;

&lt;p&gt;Building a file upload feature? Then you've already asked yourself this question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Should I be scanning these files for malware?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Yes. You should.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And the follow-up question is usually:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"How complicated is that going to be?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With &lt;strong&gt;pompelmi&lt;/strong&gt;, the answer is: barely at all.&lt;/p&gt;




&lt;h2&gt;
  
  
  🍊 What Is Pompelmi?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/pompelmi/pompelmi" rel="noopener noreferrer"&gt;Pompelmi&lt;/a&gt; is a minimal Node.js wrapper around &lt;strong&gt;ClamAV&lt;/strong&gt; — the open-source antivirus engine maintained by Cisco Talos. It scans any file and returns a typed Verdict Symbol:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Verdict&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Verdict.Clean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No threats found ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Verdict.Malicious&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A known malware signature was matched 🚨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Verdict.ScanError&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scan failed — treat the file as untrusted ⚠️&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No daemons to manage. No external API calls. No native bindings. Zero runtime dependencies.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔧 Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Install ClamAV on the Host System
&lt;/h3&gt;

&lt;p&gt;ClamAV must be present on the machine running your app. Pompelmi does not bundle or download it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;macOS:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;clamav &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; freshclam
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Linux (Debian / Ubuntu):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; clamav clamav-daemon &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;freshclam
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Windows (Chocolatey):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;choco &lt;span class="nb"&gt;install &lt;/span&gt;clamav &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;freshclam&lt;/code&gt; downloads the virus signature database. This step is essential — without an up-to-date database, ClamAV won't recognize anything.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. Install Pompelmi
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;pompelmi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done. Zero peer dependencies, zero surprises.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Quick Start
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pompelmi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/path/to/uploaded-file.zip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Malicious&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;File rejected: malware detected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "Clean"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three effective lines. That's all the complexity you need for the base case.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ How It Works Under the Hood
&lt;/h2&gt;

&lt;p&gt;Pompelmi is deliberately transparent about what it does:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Validate&lt;/strong&gt; — checks that the argument is a string and that the file exists before spawning anything&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scan&lt;/strong&gt; — spawns &lt;code&gt;clamscan --no-summary &amp;lt;filePath&amp;gt;&lt;/code&gt; as a child process and reads the exit code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Map&lt;/strong&gt; — the exit code is converted to the corresponding Verdict. Unknown codes and spawn errors reject the Promise&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No stdout parsing. No regex. No hidden magic.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛡️ A Robust Production Pattern
&lt;/h2&gt;

&lt;p&gt;In the real world you want to handle all three outcomes carefully:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pompelmi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;scanUploadedFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Clean&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`✅ File is safe: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;safe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Malicious&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`🚨 Malware detected: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;safe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;malware_detected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ScanError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;// Incomplete scan = untrusted file&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`⚠️ Scan failed, rejecting file: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;safe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scan_error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;safe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unknown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Critical scan error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;safe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;exception&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Golden rule:&lt;/strong&gt; treat &lt;code&gt;ScanError&lt;/code&gt; exactly like &lt;code&gt;Malicious&lt;/code&gt;. When in doubt, reject. A false positive is far less damaging than letting malware through undetected.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🔍 Reading the Verdict as a String
&lt;/h2&gt;

&lt;p&gt;Every Verdict Symbol exposes a &lt;code&gt;.description&lt;/code&gt; property for logging and serialisation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Clean&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;     &lt;span class="c1"&gt;// "Clean"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Malicious&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "Malicious"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ScanError&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "ScanError"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lets you save it to a database or send it over an API without comparing raw Symbols throughout your entire codebase.&lt;/p&gt;




&lt;h2&gt;
  
  
  🐳 Remote Scanning via clamd (Perfect for Docker)
&lt;/h2&gt;

&lt;p&gt;If you're running ClamAV as a separate microservice — a very common pattern in containerised setups — pompelmi supports scanning via a TCP socket:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/path/to/file.pdf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10.0.0.5&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// ClamAV container address&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3310&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;       &lt;span class="c1"&gt;// ms&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A typical &lt;code&gt;docker-compose.yml&lt;/code&gt; setup might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CLAMAV_HOST=clamav&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;CLAMAV_PORT=3310&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;clamav&lt;/span&gt;

  &lt;span class="na"&gt;clamav&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;clamav/clamav:stable&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3310:3310"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in your application code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CLAMAV_HOST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CLAMAV_PORT&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean, scalable, and the signature database updates independently from your application.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧪 Testing
&lt;/h2&gt;

&lt;p&gt;Pompelmi has a well-thought-out testing approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unit tests&lt;/strong&gt; (&lt;code&gt;test/unit.test.js&lt;/code&gt;) — run with Node's built-in test runner. They mock &lt;code&gt;nativeSpawn&lt;/code&gt; without requiring ClamAV to be installed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration tests&lt;/strong&gt; (&lt;code&gt;test/scan.test.js&lt;/code&gt;) — spawn real &lt;code&gt;clamscan&lt;/code&gt; processes against EICAR test files. They are skipped automatically if &lt;code&gt;clamscan&lt;/code&gt; is not in the PATH.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can use EICAR files to test your integration locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Download the EICAR test file (the standard antivirus test signature)&lt;/span&gt;
curl &lt;span class="nt"&gt;-o&lt;/span&gt; test-eicar.txt https://secure.eicar.org/eicar.com.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./test-eicar.txt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Malicious&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The EICAR file is not actually malicious — it's a standardised test string that every compliant antivirus engine recognises as a "safe" way to confirm detection is working.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔄 Express.js Integration Example
&lt;/h2&gt;

&lt;p&gt;Here's a complete, practical example integrating pompelmi into an Express upload endpoint using &lt;code&gt;multer&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;multer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;multer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pompelmi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;upload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;multer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/tmp/uploads/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/upload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;single&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No file provided&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// Always clean up the temp file&lt;/span&gt;
    &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlinkSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Malicious&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;422&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;File rejected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Malware detected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ScanError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;422&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;File rejected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Scan could not complete — file treated as untrusted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Verdict.Clean — proceed with your business logic&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;File accepted and is clean&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Clean up on unexpected error&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;existsSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlinkSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Internal scan error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server running on port 3000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📋 When to Use Pompelmi
&lt;/h2&gt;

&lt;p&gt;✅ &lt;strong&gt;Great fit for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;File upload features in SaaS applications&lt;/li&gt;
&lt;li&gt;Validating attachments before archiving or processing&lt;/li&gt;
&lt;li&gt;CI/CD pipelines that analyse build artefacts&lt;/li&gt;
&lt;li&gt;Environments where data must never leave your own infrastructure&lt;/li&gt;
&lt;li&gt;Teams that want security without the overhead of a managed service&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Consider supplementing with additional tools if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need protection against &lt;strong&gt;zero-day threats&lt;/strong&gt; (ClamAV is signature-based, not behavioural)&lt;/li&gt;
&lt;li&gt;You're handling extremely high-risk files in critical security contexts&lt;/li&gt;
&lt;li&gt;Your threat model includes sophisticated, targeted attacks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the vast majority of web applications that accept user uploads, pompelmi offers exactly the right level of protection for the complexity it introduces — which is close to zero.&lt;/p&gt;




&lt;h2&gt;
  
  
  🗺️ Pompelmi vs. Alternatives
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;pompelmi&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;clamscan (direct)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Managed API (e.g. VirusTotal)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Setup complexity&lt;/td&gt;
&lt;td&gt;Very low&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime dependencies&lt;/td&gt;
&lt;td&gt;Zero&lt;/td&gt;
&lt;td&gt;ClamAV&lt;/td&gt;
&lt;td&gt;HTTP client&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data leaves server&lt;/td&gt;
&lt;td&gt;❌ Never&lt;/td&gt;
&lt;td&gt;❌ Never&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zero-day detection&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Paid tiers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js integration&lt;/td&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remote/Docker support&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🔐 Security Considerations
&lt;/h2&gt;

&lt;p&gt;A few things to keep in mind when running pompelmi in production:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Keep the signature database updated.&lt;/strong&gt; ClamAV is only as good as its latest signatures. Run &lt;code&gt;freshclam&lt;/code&gt; on a schedule (daily is typical).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scan before storing.&lt;/strong&gt; Always scan the file in a temporary location before moving it to permanent storage. Never store an unscanned file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Don't rely on file extensions.&lt;/strong&gt; A &lt;code&gt;.txt&lt;/code&gt; file can contain a malicious payload. Always scan the actual binary content.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Limit file size upstream.&lt;/strong&gt; Large files slow down scans significantly. Enforce size limits at the HTTP layer before the file reaches pompelmi.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Run ClamAV as a separate user.&lt;/strong&gt; Avoid running it with root privileges. A dedicated &lt;code&gt;clamav&lt;/code&gt; system user is the standard practice.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🔗 Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;📦 &lt;a href="https://www.npmjs.com/package/pompelmi" rel="noopener noreferrer"&gt;pompelmi on npm&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🐙 &lt;a href="https://github.com/pompelmi/pompelmi" rel="noopener noreferrer"&gt;pompelmi on GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📖 &lt;a href="https://pompelmi.app" rel="noopener noreferrer"&gt;pompelmi API docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🛡️ &lt;a href="https://www.clamav.net" rel="noopener noreferrer"&gt;ClamAV official site&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🐳 &lt;a href="https://hub.docker.com/r/clamav/clamav" rel="noopener noreferrer"&gt;ClamAV Docker image&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Security doesn't have to mean complexity. Pompelmi proves that a well-scoped, focused library can handle a serious problem — malware detection — with minimal friction for the developer.&lt;/p&gt;

&lt;p&gt;If you're shipping a Node.js app that handles user files and you're not scanning them yet, there's no longer a good excuse not to. A single &lt;code&gt;npm install&lt;/code&gt; and a handful of lines stands between you and a meaningful layer of protection.&lt;/p&gt;

&lt;p&gt;Got questions or want to contribute? The project is open source and welcomes pull requests.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Found this useful? Drop a ❤️ and share it with a fellow developer building something users trust with their files.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>security</category>
      <category>npm</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Getting started with antivirus scanning in Node.js (5 minutes)</title>
      <dc:creator>Tommaso Bertocchi</dc:creator>
      <pubDate>Tue, 21 Apr 2026 07:41:42 +0000</pubDate>
      <link>https://dev.to/sonotommy/getting-started-with-antivirus-scanning-in-nodejs-5-minutes-1pl7</link>
      <guid>https://dev.to/sonotommy/getting-started-with-antivirus-scanning-in-nodejs-5-minutes-1pl7</guid>
      <description>&lt;p&gt;You've built a Node.js app that accepts file uploads. Great. Now how do you make sure those files don't contain viruses?&lt;/p&gt;

&lt;p&gt;The answer is &lt;strong&gt;ClamAV&lt;/strong&gt; — a free, open-source antivirus engine that has been around since 2001, is maintained by Cisco, and is used by thousands of applications worldwide. It runs entirely on your own machine. No subscription, no API key, no files leaving your server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;pompelmi&lt;/strong&gt; is a tiny Node.js package that calls ClamAV for you and gives back a clean result you can act on in JavaScript. Let's set it up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 — Install ClamAV
&lt;/h2&gt;

&lt;p&gt;ClamAV is a system-level tool. Install it with your operating system's package manager, not via npm.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;macOS — Homebrew&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;clamav
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Linux — Debian / Ubuntu&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; clamav
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Linux — RHEL / Fedora / CentOS&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; clamav clamav-update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Windows — Chocolatey&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;choco &lt;span class="nb"&gt;install &lt;/span&gt;clamav &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the installation worked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;clamscan &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="c"&gt;# ClamAV 1.x.x/...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now download the virus database. ClamAV ships without definitions — you need to fetch them before any scan can work:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;macOS and Windows&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;freshclam
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Linux&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;freshclam
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first &lt;code&gt;freshclam&lt;/code&gt; download takes a few minutes — the database is several hundred megabytes. Subsequent runs are incremental and fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 — Install pompelmi
&lt;/h2&gt;

&lt;p&gt;In your Node.js project directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;pompelmi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;pompelmi has &lt;strong&gt;zero runtime dependencies&lt;/strong&gt;. It uses Node's built-in &lt;code&gt;child_process&lt;/code&gt; module to call &lt;code&gt;clamscan&lt;/code&gt; and nothing else. No transitive packages to audit or update.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 — Scan your first file
&lt;/h2&gt;

&lt;p&gt;Create a file called &lt;code&gt;scan.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pompelmi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Usage: node scan.js &amp;lt;file&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Scanning:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;verdict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;verdict&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Clean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Result: Clean — no threats found.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;verdict&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Malicious&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Result: Malicious — malware detected!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;verdict&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ScanError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Result: ScanError — could not complete scan.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it against any file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node scan.js /etc/hosts
&lt;span class="c"&gt;# Scanning: /etc/hosts&lt;/span&gt;
&lt;span class="c"&gt;# Result: Clean — no threats found.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Three verdicts, one function, zero configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 — Test malware detection with EICAR
&lt;/h2&gt;

&lt;p&gt;How do you test that the malicious path actually works without using real malware? The &lt;strong&gt;EICAR test file&lt;/strong&gt; is a harmless string that every antivirus engine is required to detect as "malicious" for exactly this purpose. It was invented in 1991 and contains no actual malicious code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create the EICAR test file&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/eicar.txt

&lt;span class="c"&gt;# Scan it&lt;/span&gt;
node scan.js /tmp/eicar.txt
&lt;span class="c"&gt;# Scanning: /tmp/eicar.txt&lt;/span&gt;
&lt;span class="c"&gt;# Result: Malicious — malware detected!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see "Result: Malicious" on the EICAR file, your setup is working correctly. If you see "Clean", run &lt;code&gt;freshclam&lt;/code&gt; again — the virus database may not have downloaded properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;You now have a working scanner. The next step is wiring it into your web framework so uploads are scanned automatically.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pompelmi.app/blog/scan-file-upload-nodejs.html" rel="noopener noreferrer"&gt;How to scan file uploads for viruses in Node.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pompelmi.app/blog/pompelmi-with-express.html" rel="noopener noreferrer"&gt;Scanning file uploads with pompelmi in Express.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pompelmi.app/blog/pompelmi-with-nestjs.html" rel="noopener noreferrer"&gt;How to use pompelmi in a NestJS application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pompelmi.app/blog/pompelmi-docker-compose.html" rel="noopener noreferrer"&gt;Running pompelmi with ClamAV in Docker Compose&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://pompelmi.app/blog/nodejs-antivirus-getting-started.html" rel="noopener noreferrer"&gt;pompelmi.app&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>cybersecurity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>10 Best Open Source Projects Every Developer Should Know (Including One You've Never Heard Of)</title>
      <dc:creator>Tommaso Bertocchi</dc:creator>
      <pubDate>Mon, 20 Apr 2026 09:18:00 +0000</pubDate>
      <link>https://dev.to/sonotommy/10-best-open-source-projects-every-developer-should-know-including-one-youve-never-heard-of-3a3p</link>
      <guid>https://dev.to/sonotommy/10-best-open-source-projects-every-developer-should-know-including-one-youve-never-heard-of-3a3p</guid>
      <description>&lt;p&gt;Most developers know the big names.&lt;/p&gt;

&lt;p&gt;Docker. Postgres. VS Code.&lt;/p&gt;

&lt;p&gt;But there is an entire layer of open-source tooling that most teams still rely on paid SaaS for — secrets management, background jobs, observability, document signing, malware scanning — where the open-source alternative is already better.&lt;/p&gt;

&lt;p&gt;Here are 10 projects worth knowing in 2026.&lt;/p&gt;

&lt;p&gt;One of them, you have almost certainly never heard of.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TL;DR: open-source has caught up in nearly every category. These 10 projects cover the gaps most teams still pay to fill.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffon1preqgwa4wje04xm7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffon1preqgwa4wje04xm7.gif" alt="developers staring at code" width="384" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;That feeling when you realize the tool you've been paying for has had a better open-source version the whole time. Source: &lt;a href="https://giphy.com/gifs/southparkgifs-l3vRd3vZPrApPqzjq" rel="noopener noreferrer"&gt;Giphy&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Hoppscotch&lt;/li&gt;
&lt;li&gt;Infisical&lt;/li&gt;
&lt;li&gt;Coolify&lt;/li&gt;
&lt;li&gt;Meilisearch&lt;/li&gt;
&lt;li&gt;Trigger.dev&lt;/li&gt;
&lt;li&gt;Zed&lt;/li&gt;
&lt;li&gt;Plane&lt;/li&gt;
&lt;li&gt;OpenObserve&lt;/li&gt;
&lt;li&gt;Documenso&lt;/li&gt;
&lt;li&gt;pompelmi&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1) Hoppscotch — The API client that lives in your browser
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A lightweight, open-source API testing platform. Think Postman, but faster to open, easier to share, and fully self-hostable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; API development involves a lot of repetition — building requests, testing auth flows, inspecting headers, sharing collections with teammates. Hoppscotch cuts the friction out of all of it. It runs in the browser with no install required, syncs collections, supports REST, GraphQL, and WebSocket, and the self-hosted version gives you full control over the data.&lt;/p&gt;

&lt;p&gt;It is the kind of tool you try once and quietly stop reaching for Postman.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/hoppscotch/hoppscotch" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/hoppscotch/hoppscotch" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2F1%2Fhoppscotch%2Fhoppscotch" alt="hoppscotch preview" width="1200" height="600"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Self-host with Docker&lt;/span&gt;
docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 hoppscotch/hoppscotch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2) Infisical — Secrets management that does not make you choose between security and simplicity
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; An open-source secrets manager. Centralize environment variables, API keys, and credentials across every service, environment, and team member.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; The way most teams handle secrets is quietly catastrophic. &lt;code&gt;.env&lt;/code&gt; files checked into repos, credentials pasted in Slack, "just hardcode it for now" becoming permanent. Infisical replaces that entire pattern with a proper secrets platform — audit logs, access controls, secret versioning, native CI/CD integrations, and a self-hosted option if you cannot send credentials to a third party.&lt;/p&gt;

&lt;p&gt;The SDK integrates in three lines. The audit trail alone is worth it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/Infisical/infisical" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Infisical/infisical" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2F1%2FInfisical%2Finfisical" alt="infisical preview" width="1200" height="600"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;InfisicalClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@infisical/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InfisicalClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;INFISICAL_TOKEN&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSecret&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3) Coolify — Self-hosted Heroku that actually works
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; An open-source, self-hosted platform for deploying apps, databases, and services on your own infrastructure. It manages SSL, reverse proxying, deployments, and backups without you touching Nginx config files at 2am.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Heroku was the best PaaS experience for years. Then the free tier disappeared and the pricing got serious. Coolify gives you most of that experience on a $6/month VPS. Git push deployments, preview environments, one-click database provisioning, and a clean UI that makes self-hosting feel less like a punishment.&lt;/p&gt;

&lt;p&gt;If you have been avoiding self-hosting because it seems too complex, Coolify is the tool that changes that calculation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/coollabsio/coolify" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/coollabsio/coolify" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2F1%2Fcoollabsio%2Fcoolify" alt="coolify preview" width="1200" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3hcvc1mhqf3kz258vrvu.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3hcvc1mhqf3kz258vrvu.gif" alt="developers waiting for a deploy" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Waiting on a Heroku dyno to wake up vs watching Coolify deploy in seconds on your own server. Source: &lt;a href="https://giphy.com/gifs/fox-computer-family-guy-5nvQ7fBWhPVXXOcfRI" rel="noopener noreferrer"&gt;Giphy&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  4) Meilisearch — Search that your users will actually compliment
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A fast, typo-tolerant, open-source search engine built for developer integration. Sub-50ms responses at most scales, with a clean REST API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Most teams bolt on search as an afterthought, usually with a basic SQL &lt;code&gt;LIKE&lt;/code&gt; query that barely works. Meilisearch makes real search — typo correction, faceting, custom ranking, instant results — accessible to a project of any size without standing up a full Elasticsearch cluster.&lt;/p&gt;

&lt;p&gt;It installs in minutes, indexes in seconds, and the default ranking is good enough that most projects ship it without tuning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/meilisearch/meilisearch" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/meilisearch/meilisearch" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2F1%2Fmeilisearch%2Fmeilisearch" alt="meilisearch preview" width="1200" height="600"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MeiliSearch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;meilisearch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MeiliSearch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:7700&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;coffe maker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// typo-tolerant — returns "coffee maker" results&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5) Trigger.dev — Background jobs without the boilerplate
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; An open-source platform for writing and running background jobs, scheduled tasks, and long-running workflows directly in your codebase. It handles retries, delays, fan-out, and observability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Background job infrastructure is one of those things teams keep rebuilding from scratch — queue setup, worker processes, retry logic, dead-letter handling, monitoring. Trigger.dev wraps all of it in a clean TypeScript API. You write the job like a function, it handles the rest.&lt;/p&gt;

&lt;p&gt;The real value is the observability layer. Every run is inspectable, every step is logged, and failures are debuggable without digging through CloudWatch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/triggerdotdev/trigger.dev" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/triggerdotdev/trigger.dev" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2F1%2Ftriggerdotdev%2Ftrigger.dev" alt="trigger.dev preview" width="1200" height="600"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@trigger.dev/sdk/v3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;processUpload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;task&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;process-upload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;maxAttempts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;minTimeoutInMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fileUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// long-running logic — no timeout worries&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;heavyProcessing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fileUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;notifyUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  6) Zed — The code editor built for people who care about speed
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A high-performance, open-source code editor built in Rust. Collaborative editing built in. GPU-accelerated rendering. LSP support. Extensions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; VS Code is the default, and it is fine. Zed is for developers who have started to notice that "fine" has a hidden cost in startup time, memory, and UI lag. It opens instantly, feels native on macOS and Linux, and has multi-player editing built into the core rather than bolted on as an extension.&lt;/p&gt;

&lt;p&gt;If you have been using VS Code and occasionally wondering why your editor uses more memory than your database, Zed is worth a day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/zed-industries/zed" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/zed-industries/zed" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2F1%2Fzed-industries%2Fzed" alt="zed preview" width="1200" height="600"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  7) Plane — Project management without the enterprise bloat
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; An open-source alternative to Jira and Linear. Issues, cycles, modules, analytics, and custom workflows — fully self-hostable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Jira is powerful but notoriously slow and overengineered for most teams. Linear fixed the UX but the pricing adds up at scale and you do not own the data. Plane gives you the clean, fast project management experience without the SaaS lock-in. The UI is clean, it imports from Jira and GitHub, and the self-hosted path is well-documented.&lt;/p&gt;

&lt;p&gt;For teams that want control over their project data, this is the clearest alternative.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/makeplane/plane" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/makeplane/plane" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2F1%2Fmakeplane%2Fplane" alt="plane preview" width="1200" height="600"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  8) OpenObserve — Observability at a fraction of the cost
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; An open-source observability platform for logs, metrics, and traces. Built in Rust. Claims up to 140x lower storage costs than Elasticsearch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; The observability stack is one of the biggest hidden costs in modern infrastructure. Datadog, New Relic, and Splunk are priced for enterprises with enterprise budgets. OpenObserve is a single binary that ingests logs, metrics, and traces with a Kibana-like UI, SQL querying, and built-in alerting. The storage efficiency claim is not marketing — it uses columnar storage via Parquet under the hood.&lt;/p&gt;

&lt;p&gt;For teams running their own infrastructure, this changes the cost equation significantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/openobserve/openobserve" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/openobserve/openobserve" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2F1%2Fopenobserve%2Fopenobserve" alt="openobserve preview" width="1200" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F17y1xl53ls2wisw05iqq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F17y1xl53ls2wisw05iqq.gif" alt="a person checking logs at a computer" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Reading logs through a proper observability UI versus grepping through raw files at 3am. Source: &lt;a href="https://giphy.com/gifs/AnimationOnFOX-the-simpsons-road-to-cincinnati-season-32-ep-8-MsNaqI4G2rT1luIgve" rel="noopener noreferrer"&gt;Giphy&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  9) Documenso — Document signing you actually own
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; An open-source DocuSign alternative. Request signatures, build signing flows, manage templates, and keep the audit trail on your own infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Document signing touches legal agreements, employment contracts, NDAs, and client approvals. Sending those through a third-party SaaS means someone else's infrastructure holds your signed documents indefinitely. Documenso gives you the same core experience — email delivery, multi-party signing, completed PDF download, audit log — with full data ownership.&lt;/p&gt;

&lt;p&gt;It is one of those tools that compliance teams will push for before developers think to ask.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/documenso/documenso" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/documenso/documenso" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2F1%2Fdocumenso%2Fdocumenso" alt="documenso preview" width="1200" height="600"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  10) pompelmi — The one you have never heard of
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A minimal Node.js wrapper around &lt;a href="https://www.clamav.net/" rel="noopener noreferrer"&gt;ClamAV&lt;/a&gt; that scans any file for malware and returns a typed &lt;code&gt;Verdict&lt;/code&gt; — &lt;code&gt;Verdict.Clean&lt;/code&gt;, &lt;code&gt;Verdict.Malicious&lt;/code&gt;, or &lt;code&gt;Verdict.ScanError&lt;/code&gt;. No daemons. No cloud. No native bindings. Zero runtime dependencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Upload handling is one of the most consistently underestimated attack surfaces in web apps. File extensions lie. MIME types can be spoofed. Archives can contain nested payloads. Most teams validate file type on the frontend, accept the file, and move on — which is not a security decision, it is wishful thinking.&lt;/p&gt;

&lt;p&gt;pompelmi wraps ClamAV's real signature-based scanning in an API clean enough that there is no excuse to skip it. You get a typed result you can branch on, not a regex over stdout.&lt;/p&gt;

&lt;p&gt;The design is intentional. No cloud calls. No process you have to manage. Just spawn &lt;code&gt;clamscan&lt;/code&gt;, read the exit code, and get a symbol back. If the scan cannot complete, you get &lt;code&gt;Verdict.ScanError&lt;/code&gt; — and the library treats that as untrusted by default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/pompelmi/pompelmi" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/pompelmi/pompelmi" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2F1%2Fpompelmi%2Fpompelmi" alt="pompelmi preview" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;pompelmi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pompelmi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/path/to/upload.zip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Malicious&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;File rejected: malware detected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ScanError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// scan could not complete — treat as untrusted&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Scan incomplete, rejecting file as precaution&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you accept user uploads in a Node.js app, this is the layer that turns "we trust the file" into "we verified the file." It also supports scanning via a remote clamd instance over TCP, which means the same API works whether ClamAV runs locally or in a container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/path/to/upload.zip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;127.0.0.1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3310&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the project on the list most likely to quietly become a dependency you cannot imagine shipping without.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;These tools cover real gaps that most teams still fill with paid SaaS, manual process, or nothing at all.&lt;/p&gt;

&lt;p&gt;Some of them — like Infisical and Coolify — are already mature enough to use without caveats.&lt;/p&gt;

&lt;p&gt;Some — like Trigger.dev and OpenObserve — are moving fast and worth watching closely.&lt;/p&gt;

&lt;p&gt;And pompelmi is exactly the kind of tool that makes you wonder why upload security was ever treated as optional in the first place.&lt;/p&gt;

&lt;p&gt;Which one are you adding to your stack first?&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>devtools</category>
    </item>
    <item>
      <title>10 Best Cybersecurity Tools Every Developer Should Know (Including One You've Never Heard Of)</title>
      <dc:creator>Tommaso Bertocchi</dc:creator>
      <pubDate>Fri, 17 Apr 2026 09:50:05 +0000</pubDate>
      <link>https://dev.to/sonotommy/10-best-cybersecurity-tools-every-developer-should-know-including-one-youve-never-heard-of-598b</link>
      <guid>https://dev.to/sonotommy/10-best-cybersecurity-tools-every-developer-should-know-including-one-youve-never-heard-of-598b</guid>
      <description>&lt;p&gt;&lt;em&gt;Cybersecurity isn't just for ops teams anymore. As developers, we ship code that handles user data, processes file uploads, and talks to external services. The tools below will help you build safer applications — from scanning malware in uploaded files to auditing your dependencies.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. 🍋 pompelmi — Antivirus Scanning for Node.js
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://pompelmi.app/" rel="noopener noreferrer"&gt;pompelmi.app&lt;/a&gt; | &lt;strong&gt;npm:&lt;/strong&gt; &lt;code&gt;pompelmi&lt;/code&gt; | &lt;strong&gt;License:&lt;/strong&gt; ISC&lt;/p&gt;

&lt;p&gt;If your Node.js application accepts file uploads, &lt;strong&gt;pompelmi&lt;/strong&gt; is the tool you didn't know you needed.&lt;/p&gt;

&lt;p&gt;It's a minimal, zero-dependency wrapper around &lt;a href="https://www.clamav.net/" rel="noopener noreferrer"&gt;ClamAV&lt;/a&gt; that lets you scan any file path and get back a clean, typed result — no daemons, no cloud calls, no native bindings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pompelmi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;scanUpload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Malicious&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Upload rejected: malware detected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Verdict.Clean | Verdict.Malicious | Verdict.ScanError&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What makes it special:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One function&lt;/strong&gt; — just call &lt;code&gt;scan(path)&lt;/code&gt; and await a typed &lt;code&gt;Verdict&lt;/code&gt; Symbol&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero runtime dependencies&lt;/strong&gt; — uses Node's built-in &lt;code&gt;child_process&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-platform&lt;/strong&gt; — works on macOS, Linux, and Windows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No daemon required&lt;/strong&gt; — invokes &lt;code&gt;clamscan&lt;/code&gt; directly, no background process to manage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exit-code mapped&lt;/strong&gt; — no stdout parsing, no brittle regex&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install it in seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;pompelmi
&lt;span class="c"&gt;# macOS&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;clamav &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; freshclam
&lt;span class="c"&gt;# Linux&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; clamav clamav-daemon &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;freshclam
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're building an API that accepts PDFs, images, or documents from untrusted users, pompelmi is a one-liner that can save you from a catastrophic malware incident.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔗 Full docs, Docker guide, and API reference at &lt;a href="https://pompelmi.app/" rel="noopener noreferrer"&gt;pompelmi.app&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. 🔍 Snyk — Find and Fix Vulnerabilities in Your Code
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://snyk.io/" rel="noopener noreferrer"&gt;snyk.io&lt;/a&gt; | &lt;strong&gt;Free tier:&lt;/strong&gt; Yes&lt;/p&gt;

&lt;p&gt;Snyk is one of the most developer-friendly security tools available. It scans your project's dependencies (npm, pip, Maven, etc.), your container images, and even your Infrastructure-as-Code files for known vulnerabilities.&lt;/p&gt;

&lt;p&gt;What stands out is the &lt;strong&gt;fix PRs&lt;/strong&gt; feature — Snyk can automatically open a pull request to upgrade a vulnerable dependency. It integrates directly into GitHub, GitLab, and VS Code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; snyk
snyk auth
snyk &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Continuous dependency vulnerability scanning in CI/CD pipelines.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. 🛡️ OWASP ZAP — The Classic Web App Scanner
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://www.zaproxy.org/" rel="noopener noreferrer"&gt;zaproxy.org&lt;/a&gt; | &lt;strong&gt;License:&lt;/strong&gt; Apache 2.0&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;OWASP Zed Attack Proxy (ZAP)&lt;/strong&gt; is a battle-tested, open-source web application security scanner maintained by OWASP. It can find XSS, SQL injection, CSRF, and dozens of other vulnerabilities by actively probing your running app.&lt;/p&gt;

&lt;p&gt;It comes with both a GUI and a headless/CLI mode, making it easy to embed into your CI pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Integration and regression security testing of web apps before deployment.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. 🔐 Vault by HashiCorp — Secrets Management
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://www.vaultproject.io/" rel="noopener noreferrer"&gt;vaultproject.io&lt;/a&gt; | &lt;strong&gt;License:&lt;/strong&gt; BSL 1.1 / open-source editions available&lt;/p&gt;

&lt;p&gt;Hardcoded secrets in your codebase are a ticking time bomb. &lt;strong&gt;HashiCorp Vault&lt;/strong&gt; gives you a centralized, auditable secrets store with fine-grained access control.&lt;/p&gt;

&lt;p&gt;It supports dynamic secrets (credentials that are generated on demand and auto-expire), encryption as a service, and integrations with AWS, Kubernetes, and more.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vault kv put secret/myapp &lt;span class="nv"&gt;db_password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"supersecret"&lt;/span&gt;
vault kv get secret/myapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Teams managing API keys, database credentials, and certificates across multiple services.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. 🧱 Helmet.js — HTTP Security Headers for Express
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://helmetjs.github.io/" rel="noopener noreferrer"&gt;helmetjs.github.io&lt;/a&gt; | &lt;strong&gt;npm:&lt;/strong&gt; &lt;code&gt;helmet&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A surprising number of web vulnerabilities are mitigated simply by setting the right HTTP response headers. &lt;strong&gt;Helmet&lt;/strong&gt; is a tiny Express middleware that sets headers like &lt;code&gt;Content-Security-Policy&lt;/code&gt;, &lt;code&gt;X-Frame-Options&lt;/code&gt;, &lt;code&gt;Strict-Transport-Security&lt;/code&gt;, and more.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;helmet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;helmet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;helmet&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One line of code. Massive security improvement. No excuses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Any Node.js/Express application serving a frontend.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. 🕵️ Trivy — Container &amp;amp; IaC Vulnerability Scanner
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://trivy.dev/" rel="noopener noreferrer"&gt;trivy.dev&lt;/a&gt; | &lt;strong&gt;License:&lt;/strong&gt; Apache 2.0&lt;/p&gt;

&lt;p&gt;If you ship Docker containers, &lt;strong&gt;Trivy&lt;/strong&gt; by Aqua Security is the go-to scanner. It checks OS packages, language-specific packages, IaC misconfigurations, and even secrets accidentally baked into your image layers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;trivy image node:18-alpine
trivy fs ./myproject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's fast, has zero configuration for basic use, and integrates cleanly with GitHub Actions and other CI systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Scanning container images and repositories before pushing to production.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. 🔎 Semgrep — Static Analysis That Doesn't Suck
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://semgrep.dev/" rel="noopener noreferrer"&gt;semgrep.dev&lt;/a&gt; | &lt;strong&gt;Free tier:&lt;/strong&gt; Yes&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semgrep&lt;/strong&gt; is a fast, lightweight static analysis tool that lets you write rules in a syntax that closely mirrors the code you're analyzing. It supports 30+ languages and comes with thousands of community rules for catching common security bugs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;semgrep &lt;span class="nt"&gt;--config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;p/security-audit ./src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unlike traditional SAST tools, Semgrep rules are readable and easy to customize — you can write your own rule in minutes to enforce team-specific security patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Catching security bugs and anti-patterns during code review and CI.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. 🌐 Burp Suite Community Edition — Manual Pen Testing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://portswigger.net/burp" rel="noopener noreferrer"&gt;portswigger.net/burp&lt;/a&gt; | &lt;strong&gt;Free tier:&lt;/strong&gt; Community Edition&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Burp Suite&lt;/strong&gt; is the industry standard for manual web application penetration testing. It acts as a proxy between your browser and the server, letting you intercept, inspect, and modify HTTP/S requests in real time.&lt;/p&gt;

&lt;p&gt;The Community Edition is free and includes the intercepting proxy, repeater, decoder, and intruder tools — everything you need to manually probe your own app for logic flaws and injection points.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Deep-dive manual security testing and bug bounty research.&lt;/p&gt;




&lt;h2&gt;
  
  
  9. 🔑 age — Modern File Encryption
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://age-encryption.org/" rel="noopener noreferrer"&gt;age-encryption.org&lt;/a&gt; | &lt;strong&gt;License:&lt;/strong&gt; BSD 3-Clause&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;age&lt;/strong&gt; (pronounced like the word) is a modern, simple file encryption tool and Go library. It's designed as a safer replacement for GPG, with a much simpler interface and no key management footguns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Encrypt a file&lt;/span&gt;
age &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nv"&gt;$RECIPIENT_PUBLIC_KEY&lt;/span&gt; secret.txt &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; secret.txt.age

&lt;span class="c"&gt;# Decrypt it&lt;/span&gt;
age &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; ~/.ssh/id_ed25519 secret.txt.age &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; secret.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Encrypting secrets files, backups, and config files before storing or transmitting them.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. 📋 npm audit — The One You're Already Ignoring
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Built into npm&lt;/strong&gt; | &lt;strong&gt;Free&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Okay, this one's a reminder, not a discovery. &lt;code&gt;npm audit&lt;/code&gt; is built into every npm installation and checks your dependency tree against the GitHub Advisory Database for known CVEs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm audit
npm audit fix
npm audit fix &lt;span class="nt"&gt;--force&lt;/span&gt;  &lt;span class="c"&gt;# upgrades breaking changes too&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dirty secret is that most developers run it once and then ignore the warnings. Make it part of your CI pipeline with &lt;code&gt;npm audit --audit-level=high&lt;/code&gt; to fail builds on high-severity issues. No excuses — it's already installed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Every single Node.js project, every single time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Language/Platform&lt;/th&gt;
&lt;th&gt;Free?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;pompelmi&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Malware scanning&lt;/td&gt;
&lt;td&gt;Node.js&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Snyk&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dependency scanning&lt;/td&gt;
&lt;td&gt;Polyglot&lt;/td&gt;
&lt;td&gt;✅ (tier)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OWASP ZAP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Web app scanning&lt;/td&gt;
&lt;td&gt;Any&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HashiCorp Vault&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Secrets management&lt;/td&gt;
&lt;td&gt;Any&lt;/td&gt;
&lt;td&gt;✅ (OSS)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Helmet.js&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;HTTP headers&lt;/td&gt;
&lt;td&gt;Node.js/Express&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Trivy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Container scanning&lt;/td&gt;
&lt;td&gt;Docker/IaC&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Semgrep&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Static analysis&lt;/td&gt;
&lt;td&gt;30+ languages&lt;/td&gt;
&lt;td&gt;✅ (tier)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Burp Suite&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pen testing&lt;/td&gt;
&lt;td&gt;Web&lt;/td&gt;
&lt;td&gt;✅ (CE)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;age&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;File encryption&lt;/td&gt;
&lt;td&gt;Any&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;npm audit&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dependency audit&lt;/td&gt;
&lt;td&gt;Node.js&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Security doesn't have to be overwhelming. These ten tools cover the most common attack surfaces a typical application exposes: &lt;strong&gt;vulnerable dependencies, insecure headers, unscanned uploads, leaked secrets, and misconfigured containers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Start with the ones closest to your stack. If you're building a Node.js API that accepts file uploads, &lt;strong&gt;pompelmi&lt;/strong&gt; is the first tool you should add today — it's a &lt;code&gt;npm install&lt;/code&gt; away and could be the difference between a safe app and a headline.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Found this useful? Drop a ❤️ and share it with your team. Security is everyone's job.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>node</category>
      <category>webdev</category>
      <category>devops</category>
    </item>
    <item>
      <title>10 npm packages you will use in 2026</title>
      <dc:creator>Tommaso Bertocchi</dc:creator>
      <pubDate>Thu, 16 Apr 2026 06:59:58 +0000</pubDate>
      <link>https://dev.to/sonotommy/10-npm-packages-you-will-use-in-2026-796</link>
      <guid>https://dev.to/sonotommy/10-npm-packages-you-will-use-in-2026-796</guid>
      <description>&lt;p&gt;The npm ecosystem moves fast.&lt;/p&gt;

&lt;p&gt;Libraries you'd never heard of six months ago are now in half the starters on GitHub.&lt;br&gt;
Some are genuinely better. Some are hype.&lt;/p&gt;

&lt;p&gt;Here are 10 that I think are actually worth your time in 2026.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Hono, Drizzle, Zod, Vitest, Effect, pompelmi, ofetch, unstorage, tsx, and oslo — one for almost every layer of your stack.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  1. Hono — the web framework that actually stays out of your way
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
A ultrafast, edge-first web framework. Runs on Cloudflare Workers, Deno, Bun, Node.js — all with the same API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt;&lt;br&gt;
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.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Hono&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hono&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Hono&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;works everywhere&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;npm install hono&lt;/code&gt; — &lt;a href="https://hono.dev" rel="noopener noreferrer"&gt;honojs.dev&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  2. Drizzle ORM — SQL without losing your mind
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
A TypeScript ORM that writes SQL you'd actually recognize. Schema defined in TypeScript, queries look like SQL, types flow through automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt;&lt;br&gt;
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.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;npm install drizzle-orm&lt;/code&gt; — &lt;a href="https://orm.drizzle.team" rel="noopener noreferrer"&gt;orm.drizzle.team&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  3. Zod — runtime validation that TypeScript actually trusts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
Schema declaration and validation library. Define a shape once, get both a TypeScript type and a runtime validator.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt;&lt;br&gt;
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.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UserSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UserSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// throws if invalid&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;npm install zod&lt;/code&gt; — &lt;a href="https://zod.dev" rel="noopener noreferrer"&gt;zod.dev&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  4. Vitest — tests that don't slow you down
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
A Vite-native test runner. Jest-compatible API, but with native ESM support, instant watch mode, and built-in TypeScript support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt;&lt;br&gt;
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.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;add&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;returns correct sum&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;npm install -D vitest&lt;/code&gt; — &lt;a href="https://vitest.dev" rel="noopener noreferrer"&gt;vitest.dev&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  5. Effect — error handling the way it should work
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
A TypeScript library for writing reliable, type-safe, composable programs. Errors, async, dependencies — all tracked in the type system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;try/catch&lt;/code&gt; 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.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;effect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tryPromise&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
  &lt;span class="na"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NetworkError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Steep learning curve. Worth it for anything production-critical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;npm install effect&lt;/code&gt; — &lt;a href="https://effect.website" rel="noopener noreferrer"&gt;effect.website&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  6. pompelmi — antivirus scanning for Node.js that actually works
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
A minimal, zero-dependency wrapper around ClamAV. Scans any file and returns a typed &lt;code&gt;Verdict&lt;/code&gt; symbol — &lt;code&gt;Verdict.Clean&lt;/code&gt;, &lt;code&gt;Verdict.Malicious&lt;/code&gt;, or &lt;code&gt;Verdict.ScanError&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt;&lt;br&gt;
Most Node.js file upload handlers have no malware scanning at all.&lt;br&gt;
The ones that do usually rely on fragile stdout parsing with regex.&lt;br&gt;
pompelmi maps ClamAV exit codes directly — the stable interface — so it can't silently break between ClamAV versions.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pompelmi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Malicious&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;File rejected.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;No daemon needed by default. No runtime dependencies. No regex. Cross-platform.&lt;br&gt;
If ClamAV runs in a container, pass &lt;code&gt;host&lt;/code&gt; and &lt;code&gt;port&lt;/code&gt; and the API stays identical.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/pompelmi" rel="noopener noreferrer"&gt;
        pompelmi
      &lt;/a&gt; / &lt;a href="https://github.com/pompelmi/pompelmi" rel="noopener noreferrer"&gt;
        pompelmi
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Minimal Node.js wrapper around ClamAV — scan any file and get Clean, Malicious, or ScanError. Handles installation and database updates automatically.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/pompelmi/pompelmi/./src/grapefruit.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fpompelmi%2Fpompelmi%2FHEAD%2F.%2Fsrc%2Fgrapefruit.png" width="96" alt="pompelmi logo"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;pompelmi&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;ClamAV for humans&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://www.npmjs.com/package/pompelmi" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/afa9095da8c286a9d2f798ae9d02cfcf6db0ae0efc625cdf7ee757b8af5e9924/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f706f6d70656c6d692e737667" alt="npm version"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/95c61c397ca3825757ec835268e50886b2c10ddc4f0676e1222b19037610927f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4953432d626c75652e737667"&gt;&lt;img src="https://camo.githubusercontent.com/95c61c397ca3825757ec835268e50886b2c10ddc4f0676e1222b19037610927f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4953432d626c75652e737667" alt="license"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/489444e15856929c362ce966520a248149a338daec3ec32dec3f83554d46caca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f706c6174666f726d2d6d61634f532532302537432532304c696e757825323025374325323057696e646f77732d6c69676874677265792e737667"&gt;&lt;img src="https://camo.githubusercontent.com/489444e15856929c362ce966520a248149a338daec3ec32dec3f83554d46caca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f706c6174666f726d2d6d61634f532532302537432532304c696e757825323025374325323057696e646f77732d6c69676874677265792e737667" alt="platform"&gt;&lt;/a&gt;
  &lt;a href="https://www.npmjs.com/package/pompelmi?activeTab=dependencies" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/aae95fbaa83bc6a3f4597f3a75da45ea46ec236fc324617f0e5a2f15e07fe750/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646570656e64656e636965732d302d627269676874677265656e" alt="zero dependencies"&gt;&lt;/a&gt;
&lt;/p&gt;




&lt;p&gt;A minimal Node.js wrapper around &lt;a href="https://www.clamav.net/" rel="nofollow noopener noreferrer"&gt;ClamAV&lt;/a&gt; that scans any file and returns a typed &lt;code&gt;Verdict&lt;/code&gt; Symbol: &lt;code&gt;Verdict.Clean&lt;/code&gt;, &lt;code&gt;Verdict.Malicious&lt;/code&gt;, or &lt;code&gt;Verdict.ScanError&lt;/code&gt;. No daemons. No cloud. No native bindings. Zero runtime dependencies.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Table of contents&lt;/h2&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#quickstart" rel="noopener noreferrer"&gt;Quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#how-it-works" rel="noopener noreferrer"&gt;How it works&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/pompelmi/pompelmi#api" rel="noopener noreferrer"&gt;API&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#pompelmiscanfilepath-options" rel="noopener noreferrer"&gt;pompelmi.scan()&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#docker--remote-scanning" rel="noopener noreferrer"&gt;Docker / remote scanning&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/pompelmi/pompelmi#internal-utilities" rel="noopener noreferrer"&gt;Internal utilities&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#clamavinstaller" rel="noopener noreferrer"&gt;ClamAVInstaller()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#updateclamavdatabase" rel="noopener noreferrer"&gt;updateClamAVDatabase()&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#supported-platforms" rel="noopener noreferrer"&gt;Supported platforms&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#installing-clamav-manually" rel="noopener noreferrer"&gt;Installing ClamAV manually&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#testing" rel="noopener noreferrer"&gt;Testing&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#contributing" rel="noopener noreferrer"&gt;Contributing&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#security" rel="noopener noreferrer"&gt;Security&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;
&lt;br&gt;


&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quickstart&lt;/h2&gt;
&lt;/div&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install pompelmi&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight highlight-source-js notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; scan&lt;span class="pl-kos"&gt;,&lt;/span&gt; Verdict &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;require&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'pompelmi'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;result&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;await&lt;/span&gt; &lt;span class="pl-en"&gt;scan&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'/path/to/file.zip'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-k"&gt;if&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;result&lt;/span&gt; &lt;span class="pl-c1"&gt;===&lt;/span&gt; &lt;span class="pl-v"&gt;Verdict&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;Malicious&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-k"&gt;throw&lt;/span&gt; &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-v"&gt;Error&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'File rejected: malware detected'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How it works&lt;/h2&gt;

&lt;/div&gt;


&lt;ol&gt;

&lt;li&gt;

&lt;strong&gt;Validate&lt;/strong&gt; — pompelmi checks that the argument is a string and that the file exists before spawning anything.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Scan&lt;/strong&gt; — pompelmi spawns &lt;code&gt;clamscan --no-summary &amp;lt;filePath&amp;gt;&lt;/code&gt; as a child process and reads the exit code.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Map&lt;/strong&gt; — the exit code…&lt;/li&gt;

&lt;/ol&gt;
&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/pompelmi/pompelmi" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;npm install pompelmi&lt;/code&gt; — &lt;a href="https://pompelmi.app" rel="noopener noreferrer"&gt;pompelmi.app&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  7. ofetch — fetch that behaves like you expect
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
A better &lt;code&gt;fetch&lt;/code&gt; wrapper from the UnJS team. Auto-parses JSON, smart retries, proper error throwing, and works in Node, browsers, and edge runtimes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt;&lt;br&gt;
Native &lt;code&gt;fetch&lt;/code&gt; is fine until you need error handling, and then you realize you have to check &lt;code&gt;res.ok&lt;/code&gt; yourself every single time. ofetch throws on non-2xx responses by default, handles JSON automatically, and adds retry logic with a single option.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ofetch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ofetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;ofetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tommy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;npm install ofetch&lt;/code&gt; — &lt;a href="https://github.com/unjs/ofetch" rel="noopener noreferrer"&gt;github.com/unjs/ofetch&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  8. unstorage — one API for every storage backend
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
A universal key-value storage layer. Same API whether you're writing to memory, Redis, Cloudflare KV, localStorage, the filesystem, or a database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt;&lt;br&gt;
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.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createStorage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unstorage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;redisDriver&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unstorage/drivers/redis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createStorage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;redisDriver&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;REDIS_URL&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;session:abc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;session:abc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;npm install unstorage&lt;/code&gt; — &lt;a href="https://unstorage.unjs.io" rel="noopener noreferrer"&gt;unstorage.unjs.io&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  9. tsx — run TypeScript without a build step
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
A CLI tool that runs &lt;code&gt;.ts&lt;/code&gt; files directly in Node.js. Drop-in replacement for &lt;code&gt;node&lt;/code&gt;, powered by esbuild.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;ts-node&lt;/code&gt; is slow. &lt;code&gt;tsx&lt;/code&gt; is fast. Starts instantly, handles modern ESM TypeScript, and requires zero configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tsx src/index.ts
&lt;span class="c"&gt;# or&lt;/span&gt;
tsx watch src/index.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace this in your &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tsx watch src/index.ts"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;npm install -D tsx&lt;/code&gt; — &lt;a href="https://tsx.is" rel="noopener noreferrer"&gt;tsx.is&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  10. oslo — auth primitives without the framework lock-in
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
A collection of small, focused auth utilities: CSRF tokens, OTP generation, cookie handling, encoding, timing-safe comparison. From the Lucia auth team.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt;&lt;br&gt;
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.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;generateRandomString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;alphabet&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;oslo/crypto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TOTP&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;oslo/otp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generateRandomString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;alphabet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0-9&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;totp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TOTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SHA-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;totp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;npm install oslo&lt;/code&gt; — &lt;a href="https://oslo.js.org" rel="noopener noreferrer"&gt;oslo.js.org&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The list at a glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;One-liner&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hono&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Framework&lt;/td&gt;
&lt;td&gt;Edge-native, framework-agnostic web server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;drizzle-orm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;Type-safe ORM, no codegen&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;zod&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Validation&lt;/td&gt;
&lt;td&gt;Schema → TypeScript type + runtime validation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vitest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Testing&lt;/td&gt;
&lt;td&gt;Fast Jest-compatible test runner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;effect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reliability&lt;/td&gt;
&lt;td&gt;Type-safe errors and async composition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pompelmi&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;File antivirus scanning via ClamAV&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ofetch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;HTTP&lt;/td&gt;
&lt;td&gt;fetch that handles errors and JSON automatically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;unstorage&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Storage&lt;/td&gt;
&lt;td&gt;Universal key-value storage across backends&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tsx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;DX&lt;/td&gt;
&lt;td&gt;Run TypeScript files instantly, no config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;oslo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;Low-level auth primitives, no framework assumptions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;Which of these are already in your stack — and which ones are you trying next?&lt;/p&gt;

&lt;p&gt;I'm especially curious if anyone has a better alternative to &lt;code&gt;effect&lt;/code&gt; for typed error handling without the learning curve.&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I tried every Node.js antivirus library. Here's what I found.</title>
      <dc:creator>Tommaso Bertocchi</dc:creator>
      <pubDate>Wed, 15 Apr 2026 17:58:49 +0000</pubDate>
      <link>https://dev.to/sonotommy/i-tried-every-nodejs-antivirus-library-heres-what-i-found-122j</link>
      <guid>https://dev.to/sonotommy/i-tried-every-nodejs-antivirus-library-heres-what-i-found-122j</guid>
      <description>&lt;p&gt;Most Node.js file upload handlers look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/upload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;single&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;No scan. No check. Just trust.&lt;/p&gt;

&lt;p&gt;That's fine until someone uploads a malware-laced PDF to your SaaS and your enterprise customer's IT team starts asking questions.&lt;/p&gt;

&lt;p&gt;I went looking for a proper antivirus solution for Node.js. Here's everything I found — and why most of it is worse than it looks.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Most Node.js antivirus libraries are either abandoned, overly complex, or rely on fragile stdout parsing. &lt;a href="https://pompelmi.app" rel="noopener noreferrer"&gt;pompelmi&lt;/a&gt; is the one that actually does it right — zero dependencies, typed verdicts, and direct ClamAV exit code mapping with no regex.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  What I was actually looking for
&lt;/h2&gt;

&lt;p&gt;Before I started, I wrote down my requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Works in a real production Node.js app (not a script)&lt;/li&gt;
&lt;li&gt;Doesn't require me to run a background daemon 24/7 for single-scan use cases&lt;/li&gt;
&lt;li&gt;Returns typed results I can actually &lt;code&gt;switch&lt;/code&gt; on&lt;/li&gt;
&lt;li&gt;Actively maintained&lt;/li&gt;
&lt;li&gt;Zero or minimal runtime dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Spoiler: most libraries fail at least two of these.&lt;/p&gt;


&lt;h2&gt;
  
  
  The landscape (as of 2025)
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. &lt;code&gt;clamscan&lt;/code&gt; (npm)
&lt;/h3&gt;

&lt;p&gt;The oldest and most-starred option. Wraps ClamAV and has been around since 2014.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Spawns &lt;code&gt;clamscan&lt;/code&gt; or connects to &lt;code&gt;clamd&lt;/code&gt; daemon. Returns a result object.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; It parses stdout with regex patterns. That's a brittle contract — ClamAV output format changes between versions, and your regex silently breaks. I've been burned by this in production. The library also has a handful of long-standing open issues around false negatives on certain output formats.&lt;/p&gt;

&lt;p&gt;It works. But you're trusting regex to stand between you and malware.&lt;/p&gt;


&lt;h3&gt;
  
  
  2. &lt;code&gt;clamdjs&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Connects to a running &lt;code&gt;clamd&lt;/code&gt; daemon via TCP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; You have to run a daemon. For many setups — serverless functions, ephemeral containers, low-traffic apps — spinning up a persistent background service just to occasionally scan a file is overkill. Also, &lt;code&gt;clamdjs&lt;/code&gt; hasn't seen meaningful updates in years.&lt;/p&gt;


&lt;h3&gt;
  
  
  3. Random VirusTotal API wrappers
&lt;/h3&gt;

&lt;p&gt;These exist. They send your files to VirusTotal's API and return scan results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; You're uploading potentially sensitive user files to a third-party service. For anything with PII, healthcare data, or enterprise contracts, that's a non-starter. Also rate limits, latency, and cost.&lt;/p&gt;


&lt;h3&gt;
  
  
  4. Cloud-native options (AWS Malware Protection, GCP Security Command Center)
&lt;/h3&gt;

&lt;p&gt;If you're already deep in AWS or GCP, these exist and work well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; Vendor lock-in, cost, and setup complexity. Sometimes you just want to &lt;code&gt;await scan(file)&lt;/code&gt; and move on.&lt;/p&gt;


&lt;h2&gt;
  
  
  pompelmi: the one I actually kept
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/pompelmi" rel="noopener noreferrer"&gt;
        pompelmi
      &lt;/a&gt; / &lt;a href="https://github.com/pompelmi/pompelmi" rel="noopener noreferrer"&gt;
        pompelmi
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Minimal Node.js wrapper around ClamAV — scan any file and get Clean, Malicious, or ScanError. Handles installation and database updates automatically.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/pompelmi/pompelmi/./src/grapefruit.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fpompelmi%2Fpompelmi%2FHEAD%2F.%2Fsrc%2Fgrapefruit.png" width="96" alt="pompelmi logo"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;pompelmi&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;ClamAV for humans&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://www.npmjs.com/package/pompelmi" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/afa9095da8c286a9d2f798ae9d02cfcf6db0ae0efc625cdf7ee757b8af5e9924/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f706f6d70656c6d692e737667" alt="npm version"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/95c61c397ca3825757ec835268e50886b2c10ddc4f0676e1222b19037610927f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4953432d626c75652e737667"&gt;&lt;img src="https://camo.githubusercontent.com/95c61c397ca3825757ec835268e50886b2c10ddc4f0676e1222b19037610927f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4953432d626c75652e737667" alt="license"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/489444e15856929c362ce966520a248149a338daec3ec32dec3f83554d46caca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f706c6174666f726d2d6d61634f532532302537432532304c696e757825323025374325323057696e646f77732d6c69676874677265792e737667"&gt;&lt;img src="https://camo.githubusercontent.com/489444e15856929c362ce966520a248149a338daec3ec32dec3f83554d46caca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f706c6174666f726d2d6d61634f532532302537432532304c696e757825323025374325323057696e646f77732d6c69676874677265792e737667" alt="platform"&gt;&lt;/a&gt;
  &lt;a href="https://www.npmjs.com/package/pompelmi?activeTab=dependencies" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/aae95fbaa83bc6a3f4597f3a75da45ea46ec236fc324617f0e5a2f15e07fe750/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646570656e64656e636965732d302d627269676874677265656e" alt="zero dependencies"&gt;&lt;/a&gt;
&lt;/p&gt;




&lt;p&gt;A minimal Node.js wrapper around &lt;a href="https://www.clamav.net/" rel="nofollow noopener noreferrer"&gt;ClamAV&lt;/a&gt; that scans any file and returns a typed &lt;code&gt;Verdict&lt;/code&gt; Symbol: &lt;code&gt;Verdict.Clean&lt;/code&gt;, &lt;code&gt;Verdict.Malicious&lt;/code&gt;, or &lt;code&gt;Verdict.ScanError&lt;/code&gt;. No daemons. No cloud. No native bindings. Zero runtime dependencies.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Table of contents&lt;/h2&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#quickstart" rel="noopener noreferrer"&gt;Quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#how-it-works" rel="noopener noreferrer"&gt;How it works&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/pompelmi/pompelmi#api" rel="noopener noreferrer"&gt;API&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#pompelmiscanfilepath-options" rel="noopener noreferrer"&gt;pompelmi.scan()&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#docker--remote-scanning" rel="noopener noreferrer"&gt;Docker / remote scanning&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/pompelmi/pompelmi#internal-utilities" rel="noopener noreferrer"&gt;Internal utilities&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#clamavinstaller" rel="noopener noreferrer"&gt;ClamAVInstaller()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#updateclamavdatabase" rel="noopener noreferrer"&gt;updateClamAVDatabase()&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#supported-platforms" rel="noopener noreferrer"&gt;Supported platforms&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#installing-clamav-manually" rel="noopener noreferrer"&gt;Installing ClamAV manually&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#testing" rel="noopener noreferrer"&gt;Testing&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#contributing" rel="noopener noreferrer"&gt;Contributing&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#security" rel="noopener noreferrer"&gt;Security&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/pompelmi/pompelmi#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;
&lt;br&gt;


&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quickstart&lt;/h2&gt;
&lt;/div&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install pompelmi&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight highlight-source-js notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; scan&lt;span class="pl-kos"&gt;,&lt;/span&gt; Verdict &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;require&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'pompelmi'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;result&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;await&lt;/span&gt; &lt;span class="pl-en"&gt;scan&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'/path/to/file.zip'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-k"&gt;if&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;result&lt;/span&gt; &lt;span class="pl-c1"&gt;===&lt;/span&gt; &lt;span class="pl-v"&gt;Verdict&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;Malicious&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-k"&gt;throw&lt;/span&gt; &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-v"&gt;Error&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'File rejected: malware detected'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How it works&lt;/h2&gt;

&lt;/div&gt;


&lt;ol&gt;

&lt;li&gt;

&lt;strong&gt;Validate&lt;/strong&gt; — pompelmi checks that the argument is a string and that the file exists before spawning anything.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Scan&lt;/strong&gt; — pompelmi spawns &lt;code&gt;clamscan --no-summary &amp;lt;filePath&amp;gt;&lt;/code&gt; as a child process and reads the exit code.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Map&lt;/strong&gt; — the exit code…&lt;/li&gt;

&lt;/ol&gt;
&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/pompelmi/pompelmi" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;pompelmi is a Node.js antivirus library built around one idea: &lt;strong&gt;don't parse stdout, map exit codes directly&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;ClamAV already communicates via exit codes. &lt;code&gt;0&lt;/code&gt; = clean. &lt;code&gt;1&lt;/code&gt; = malware found. &lt;code&gt;2&lt;/code&gt; = error. pompelmi maps these directly to typed verdict symbols. No regex. No stdout parsing. No silent failures.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @pompelmi/probe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ClamAV needs to be present on the host (one-time setup):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# macOS&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;clamav &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; freshclam

&lt;span class="c"&gt;# Ubuntu/Debian&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; clamav &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;freshclam

&lt;span class="c"&gt;# Windows&lt;/span&gt;
choco &lt;span class="nb"&gt;install &lt;/span&gt;clamav &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;pompelmi automatically detects whether your virus definitions are up-to-date and skips &lt;code&gt;freshclam&lt;/code&gt; if they already are. No redundant downloads.&lt;/p&gt;

&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@pompelmi/probe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/path/to/uploaded-file.pdf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Clean&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;// Safe to process&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Malicious&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;// Reject and alert&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ScanError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;// Handle gracefully&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Typed. Exhaustive. No strings to compare, no regex, no &lt;code&gt;result.isInfected&lt;/code&gt; booleans with unclear semantics.&lt;/p&gt;

&lt;h3&gt;
  
  
  What makes it different
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;No stdout parsing.&lt;/strong&gt;&lt;br&gt;
Every other library I tested parses ClamAV's human-readable output. pompelmi uses exit codes exclusively — the stable, documented interface ClamAV actually exposes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No daemon required.&lt;/strong&gt;&lt;br&gt;
pompelmi calls &lt;code&gt;clamscan&lt;/code&gt; directly via Node's built-in &lt;code&gt;child_process&lt;/code&gt;. No background process to manage. Works in Lambda, in Docker, in a plain old Express app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zero runtime dependencies.&lt;/strong&gt;&lt;br&gt;
The entire library relies on Node.js built-ins. Nothing to audit, nothing to patch, nothing that breaks on a minor version bump.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-platform.&lt;/strong&gt;&lt;br&gt;
macOS, Linux, and Windows all work with the same code. The ClamAV install step varies per OS; the Node.js API doesn't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Typed verdicts.&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;Verdict.Clean&lt;/code&gt;, &lt;code&gt;Verdict.Malicious&lt;/code&gt;, &lt;code&gt;Verdict.ScanError&lt;/code&gt; — symbols, not strings. TypeScript narrows correctly. You can't typo &lt;code&gt;"malicous"&lt;/code&gt; at 2am and ship a broken check.&lt;/p&gt;




&lt;h2&gt;
  
  
  A realistic Express upload handler
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;multer&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;multer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@pompelmi/probe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs/promises&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;upload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;multer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/tmp/uploads&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/upload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;single&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Malicious&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;File rejected: malware detected.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ScanError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Scan failed. Please retry.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Verdict.Clean — proceed with processing&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/var/uploads&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalname&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dest&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unexpected error.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean, safe, and explicit about every possible outcome.&lt;/p&gt;




&lt;h2&gt;
  
  
  The verdict (pun intended)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Library&lt;/th&gt;
&lt;th&gt;Maintained&lt;/th&gt;
&lt;th&gt;No daemon needed&lt;/th&gt;
&lt;th&gt;Typed results&lt;/th&gt;
&lt;th&gt;No stdout parsing&lt;/th&gt;
&lt;th&gt;Zero deps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;clamscan&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Partially&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;clamdjs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VirusTotal wrappers&lt;/td&gt;
&lt;td&gt;Varies&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Varies&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;pompelmi&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you're building a Node.js app that handles file uploads in 2025, you should be scanning them.&lt;/p&gt;

&lt;p&gt;pompelmi makes it as easy as it should be.&lt;/p&gt;




&lt;p&gt;Are you scanning user uploads in your app? What's your current setup — and what's the biggest friction point you've hit?&lt;/p&gt;

&lt;p&gt;Drop it in the comments. I'm curious whether anyone has a pattern I haven't seen.&lt;/p&gt;

</description>
      <category>node</category>
      <category>security</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>it will be for all 2026</title>
      <dc:creator>Tommaso Bertocchi</dc:creator>
      <pubDate>Sun, 12 Apr 2026 17:35:58 +0000</pubDate>
      <link>https://dev.to/sonotommy/it-will-be-for-all-2026-4bm5</link>
      <guid>https://dev.to/sonotommy/it-will-be-for-all-2026-4bm5</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/sonotommy/10-open-source-projects-youll-actually-use-in-2026-2ig9" class="crayons-story__hidden-navigation-link"&gt;10 Open-Source Projects You’ll Actually Use in 2026&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/sonotommy" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3399256%2F111d6919-72dc-4992-a6c6-2b20a4ccf85b.jpeg" alt="sonotommy profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/sonotommy" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Tommaso Bertocchi
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Tommaso Bertocchi
                
              
              &lt;div id="story-author-preview-content-3350792" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/sonotommy" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3399256%2F111d6919-72dc-4992-a6c6-2b20a4ccf85b.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Tommaso Bertocchi&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/sonotommy/10-open-source-projects-youll-actually-use-in-2026-2ig9" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 14&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/sonotommy/10-open-source-projects-youll-actually-use-in-2026-2ig9" id="article-link-3350792"&gt;
          10 Open-Source Projects You’ll Actually Use in 2026
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/sonotommy/10-open-source-projects-youll-actually-use-in-2026-2ig9" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;20&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/sonotommy/10-open-source-projects-youll-actually-use-in-2026-2ig9#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              1&lt;span class="hidden s:inline"&gt; comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>read this</title>
      <dc:creator>Tommaso Bertocchi</dc:creator>
      <pubDate>Sun, 12 Apr 2026 17:27:09 +0000</pubDate>
      <link>https://dev.to/sonotommy/read-this-2oah</link>
      <guid>https://dev.to/sonotommy/read-this-2oah</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/sonotommy/i-spent-3-hours-adding-antivirus-to-my-express-app-then-i-reduced-it-to-3-lines-2dm7" class="crayons-story__hidden-navigation-link"&gt;I Spent 3 Hours Adding Antivirus to My Express App. Then I Reduced It to 3 Lines.&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/sonotommy" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3399256%2F111d6919-72dc-4992-a6c6-2b20a4ccf85b.jpeg" alt="sonotommy profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/sonotommy" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Tommaso Bertocchi
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Tommaso Bertocchi
                
              
              &lt;div id="story-author-preview-content-3489863" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/sonotommy" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3399256%2F111d6919-72dc-4992-a6c6-2b20a4ccf85b.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Tommaso Bertocchi&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/sonotommy/i-spent-3-hours-adding-antivirus-to-my-express-app-then-i-reduced-it-to-3-lines-2dm7" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 12&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/sonotommy/i-spent-3-hours-adding-antivirus-to-my-express-app-then-i-reduced-it-to-3-lines-2dm7" id="article-link-3489863"&gt;
          I Spent 3 Hours Adding Antivirus to My Express App. Then I Reduced It to 3 Lines.
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/javascript"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;javascript&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/node"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;node&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/security"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;security&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/beginners"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;beginners&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/sonotommy/i-spent-3-hours-adding-antivirus-to-my-express-app-then-i-reduced-it-to-3-lines-2dm7" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;20&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/sonotommy/i-spent-3-hours-adding-antivirus-to-my-express-app-then-i-reduced-it-to-3-lines-2dm7#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              2&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>I Spent 3 Hours Adding Antivirus to My Express App. Then I Reduced It to 3 Lines.</title>
      <dc:creator>Tommaso Bertocchi</dc:creator>
      <pubDate>Sun, 12 Apr 2026 09:51:23 +0000</pubDate>
      <link>https://dev.to/sonotommy/i-spent-3-hours-adding-antivirus-to-my-express-app-then-i-reduced-it-to-3-lines-2dm7</link>
      <guid>https://dev.to/sonotommy/i-spent-3-hours-adding-antivirus-to-my-express-app-then-i-reduced-it-to-3-lines-2dm7</guid>
      <description>&lt;p&gt;Two years ago, I shipped my first production app with file uploads. A week later, my mentor asked: "Are you scanning those files for malware?"&lt;/p&gt;

&lt;p&gt;I wasn't.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Google Rabbit Hole
&lt;/h2&gt;

&lt;p&gt;Like any developer, I Googled "node js antivirus file upload." Here's what I found:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ClamAV&lt;/strong&gt; — the open-source standard. Great! Let's use it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;clamscan npm package&lt;/strong&gt; — 47 configuration options.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;clamav.js&lt;/strong&gt; — requires running &lt;code&gt;clamd&lt;/code&gt; daemon.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Various tutorials&lt;/strong&gt; — "First, configure your socket connection..."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I just wanted to scan a file. Why did I need to understand Unix sockets?&lt;/p&gt;

&lt;h2&gt;
  
  
  My First Attempt
&lt;/h2&gt;

&lt;p&gt;After an hour of reading docs, I had something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;NodeClam&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;clamscan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clamscan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NodeClam&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;removeInfected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;quarantineInfected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;scanLog&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;debugMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;fileList&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;scanRecursively&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;clamscan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/usr/bin/clamscan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;scanArchives&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;clamdscan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/var/run/clamav/clamd.ctl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;localFallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/usr/bin/clamdscan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;configFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;multiscan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;reloadDb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;bypassTest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;preference&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;clamdscan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// ... 30 more lines to actually scan a file&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It didn't work. The socket path was wrong on my Mac. I spent another hour debugging.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Daemon Problem
&lt;/h2&gt;

&lt;p&gt;Most ClamAV wrappers assume you're running &lt;code&gt;clamd&lt;/code&gt; — a background daemon that keeps virus definitions in memory for faster scanning.&lt;/p&gt;

&lt;p&gt;This makes sense for high-throughput enterprise systems. But I was building a side project. I didn't want to manage a daemon. I didn't want to configure systemd. I didn't want to think about socket permissions.&lt;/p&gt;

&lt;p&gt;I just wanted to answer one question: &lt;strong&gt;is this file safe?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Actually Needed
&lt;/h2&gt;

&lt;p&gt;After three hours of frustration, I wrote down what I actually wanted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pompelmi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/path/to/upload.zip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Verdict.Clean | Verdict.Malicious | Verdict.ScanError — that's it&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No daemon. No configuration object. No socket paths. Just a function that takes a file and returns an answer.&lt;/p&gt;

&lt;p&gt;So I built it.&lt;/p&gt;

&lt;h2&gt;
  
  
  pompelmi: ClamAV for Humans
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pompelmi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pompelmi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/path/to/file.zip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Malicious&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;File rejected: malware detected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the entire API. One function. Three possible results — typed as Symbols, so no typos, no accidental string mismatches.&lt;/p&gt;

&lt;p&gt;Here's the same Express middleware, before and after:&lt;/p&gt;

&lt;h3&gt;
  
  
  Before (47 lines)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;NodeClam&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;clamscan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;multer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;multer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// ... 35 lines of configuration ...&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/upload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;single&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clam&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;clamscan&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isInfected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;viruses&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;clam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isInfected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isInfected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlinkSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Malware detected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;viruses&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Is this a scan error or a config error? Who knows!&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Scan failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  After (12 lines)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pompelmi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;multer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;multer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/upload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;single&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Malicious&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlinkSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Malware detected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ScanError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Scan couldn't complete — treat as untrusted&lt;/span&gt;
    &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlinkSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;File rejected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How It Works (The Boring Way)
&lt;/h2&gt;

&lt;p&gt;pompelmi doesn't do anything clever:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check that the file exists&lt;/li&gt;
&lt;li&gt;Spawn &lt;code&gt;clamscan --no-summary &amp;lt;path&amp;gt;&lt;/code&gt; using Node's native &lt;code&gt;child_process&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Read the exit code&lt;/li&gt;
&lt;li&gt;Map it to a Symbol&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No stdout parsing. No regex. No daemon. No socket. No third-party spawn library. Just a child process and an exit code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Exit 0 → Verdict.Clean
Exit 1 → Verdict.Malicious
Exit 2 → Verdict.ScanError
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ClamAV has been doing this reliably for 20 years. I just wrapped it in a function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Symbols, Not Strings?
&lt;/h2&gt;

&lt;p&gt;Since v1.2.0, scan results are &lt;code&gt;Symbol&lt;/code&gt;s, not plain strings. This means:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ✅ This works&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Verdict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Malicious&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ❌ This will never match — intentionally&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Malicious&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It prevents a whole class of bugs where you typo a string comparison (&lt;code&gt;'malicious'&lt;/code&gt; vs &lt;code&gt;'Malicious'&lt;/code&gt;) and your security check silently does nothing. The compiler catches it for you.&lt;/p&gt;

&lt;p&gt;If you need the verdict as a string for logging, each Symbol has a &lt;code&gt;.description&lt;/code&gt; property:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "Clean", "Malicious", or "ScanError"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Upgrading from v1.1.x?&lt;/strong&gt; Replace any &lt;code&gt;result === 'Clean'&lt;/code&gt; checks with &lt;code&gt;result === Verdict.Clean&lt;/code&gt; (and same for &lt;code&gt;Malicious&lt;/code&gt; and &lt;code&gt;ScanError&lt;/code&gt;). Don't forget to import &lt;code&gt;Verdict&lt;/code&gt; alongside &lt;code&gt;scan&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  "But What About Performance?"
&lt;/h2&gt;

&lt;p&gt;Yes, spawning &lt;code&gt;clamscan&lt;/code&gt; for every file is slower than using the daemon. Each scan loads the virus database from disk (~300MB).&lt;/p&gt;

&lt;p&gt;For a side project handling 100 uploads/day? Doesn't matter.&lt;/p&gt;

&lt;p&gt;For a startup processing 10,000 files/hour? You probably have a dedicated security engineer who knows how to configure &lt;code&gt;clamd&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;pompelmi is for the 99% of developers who just need &lt;em&gt;something&lt;/em&gt; — and "slow but working" beats "fast but misconfigured."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Point
&lt;/h2&gt;

&lt;p&gt;Developer tools should meet you where you are.&lt;/p&gt;

&lt;p&gt;When I was a junior developer, I didn't need 47 configuration options. I needed one function that worked. I needed to ship something on Friday and not think about Unix sockets.&lt;/p&gt;

&lt;p&gt;If you're building something bigger, you'll outgrow pompelmi. That's fine. By then, you'll understand &lt;em&gt;why&lt;/em&gt; you need the daemon, and configuring it won't feel like dark magic.&lt;/p&gt;

&lt;p&gt;But if you're building your first app with file uploads, and you just want to scan for malware without a 3-hour detour — &lt;code&gt;npm install pompelmi&lt;/code&gt;.&lt;/p&gt;






&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;pompelmi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/pompelmi/pompelmi" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.npmjs.com/package/pompelmi" rel="noopener noreferrer"&gt;npm&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;pompelmi is Italian for "grapefruits." I named it that because I was eating one when I finally got the code working at 2am. Sometimes that's all the reason you need.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>security</category>
      <category>beginners</category>
    </item>
    <item>
      <title>10 Tools That Will Instantly Make Your Coding Projects Better</title>
      <dc:creator>Tommaso Bertocchi</dc:creator>
      <pubDate>Fri, 03 Apr 2026 09:03:50 +0000</pubDate>
      <link>https://dev.to/sonotommy/10-tools-that-will-instantly-make-your-coding-projects-better-1eef</link>
      <guid>https://dev.to/sonotommy/10-tools-that-will-instantly-make-your-coding-projects-better-1eef</guid>
      <description>&lt;p&gt;Most coding projects do not fail because the idea was bad.&lt;/p&gt;

&lt;p&gt;They fail because everything around the code is weak.&lt;/p&gt;

&lt;p&gt;The deploy process is manual.&lt;/p&gt;

&lt;p&gt;The API contract lives in someone's head.&lt;/p&gt;

&lt;p&gt;Errors show up first in production.&lt;/p&gt;

&lt;p&gt;Dependencies age quietly until they become a problem.&lt;/p&gt;

&lt;p&gt;Uploads get trusted way too easily.&lt;/p&gt;

&lt;p&gt;Nobody has a clean picture of how the system actually works.&lt;/p&gt;

&lt;p&gt;That is the part a lot of teams underestimate.&lt;/p&gt;

&lt;p&gt;Good projects are not just built with good code.&lt;/p&gt;

&lt;p&gt;They are built with good systems around the code.&lt;/p&gt;

&lt;p&gt;So this is not a random list of apps.&lt;/p&gt;

&lt;p&gt;These are 10 tools that make coding projects feel more professional, more reliable, more secure, and much easier to ship.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TL;DR: Better projects usually come from stronger workflow, testing, observability, documentation, dependency hygiene, and security, not just smarter features.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fytknrcugcpceeb9l9wbj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fytknrcugcpceeb9l9wbj.gif" alt="South Park developers staring at computer screens" width="384" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The moment you realize the feature works, but the project still feels one bad deploy away from chaos. Source: &lt;a href="https://giphy.com/gifs/southparkgifs-l3vRd3vZPrApPqzjq" rel="noopener noreferrer"&gt;South Park on Giphy&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;GitHub Actions&lt;/li&gt;
&lt;li&gt;Postman&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Sentry&lt;/li&gt;
&lt;li&gt;Playwright&lt;/li&gt;
&lt;li&gt;Swagger / OpenAPI&lt;/li&gt;
&lt;li&gt;pompelmi&lt;/li&gt;
&lt;li&gt;Dependabot&lt;/li&gt;
&lt;li&gt;Excalidraw&lt;/li&gt;
&lt;li&gt;Raycast&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1) GitHub Actions — Stop shipping manually
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; GitHub's built-in automation layer for CI, CD, releases, scheduled jobs, and repo workflows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it improves your project:&lt;/strong&gt; It turns quality checks from a vague team habit into a repeatable system. Linting, tests, builds, previews, and deploy gates stop depending on who remembered what.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; pull request checks, automated releases, scheduled maintenance jobs, deployment pipelines, repo housekeeping.&lt;/p&gt;

&lt;p&gt;The fastest way to make a repo feel serious is to make every change prove itself before it lands. Even a small workflow that runs install, lint, test, and build on every PR removes a huge amount of avoidable drama.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://docs.github.com/en/actions" rel="noopener noreferrer"&gt;Official&lt;/a&gt; · &lt;a href="https://github.com/actions/starter-workflows" rel="noopener noreferrer"&gt;Representative repo&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/actions" rel="noopener noreferrer"&gt;
        actions
      &lt;/a&gt; / &lt;a href="https://github.com/actions/starter-workflows" rel="noopener noreferrer"&gt;
        starter-workflows
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Accelerating new GitHub Actions workflows 
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://avatars0.githubusercontent.com/u/44036562?s=100&amp;amp;v=4"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars0.githubusercontent.com%2Fu%2F44036562%3Fs%3D100%26v%3D4"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Starter Workflows&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;These are the workflow files for helping people get started with GitHub Actions.  They're presented whenever you start to create a new GitHub Actions workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you want to get started with GitHub Actions, you can use these starter workflows by clicking the "Actions" tab in the repository where you want to create a workflow.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/5510c8300d37413d04ca9102a8f1038208a3818fd8d94b26339256a0855d6924/68747470733a2f2f64337676366c703535716a6171632e636c6f756466726f6e742e6e65742f6974656d732f3335334133703359327833633274324e306330312f496d616765253230323031392d30382d32372532306174253230332e32352e3037253230504d2e706e67"&gt;&lt;img src="https://camo.githubusercontent.com/5510c8300d37413d04ca9102a8f1038208a3818fd8d94b26339256a0855d6924/68747470733a2f2f64337676366c703535716a6171632e636c6f756466726f6e742e6e65742f6974656d732f3335334133703359327833633274324e306330312f496d616765253230323031392d30382d32372532306174253230332e32352e3037253230504d2e706e67"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Note&lt;/h3&gt;
&lt;/div&gt;

&lt;p&gt;Thank you for your interest in this GitHub repo, however, right now we are not taking contributions.&lt;/p&gt;

&lt;p&gt;We continue to focus our resources on strategic areas that help our customers be successful while making developers' lives easier. While GitHub Actions remains a key part of this vision, we are allocating resources towards other areas of Actions and are not taking contributions to this repository at this time. The GitHub public roadmap is the best place to follow along for any updates on features we’re working on and what stage they’re in.&lt;/p&gt;

&lt;p&gt;We…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/actions/starter-workflows" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;&lt;br&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ci&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;verify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;22&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run lint&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxknr34f6np28h96a1kx.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxknr34f6np28h96a1kx.gif" alt="Family Guy staring at a computer" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;When the team discovers that "our deploy checklist" was actually just one person's memory. Source: &lt;a href="https://giphy.com/gifs/fox-computer-family-guy-5nvQ7fBWhPVXXOcfRI" rel="noopener noreferrer"&gt;Family Guy on Giphy&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  2) Postman — Make your API usable by more than its author
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; An API platform for sending requests, organizing collections, sharing environments, and testing real responses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it improves your project:&lt;/strong&gt; Good APIs are not just endpoints that return JSON. They are endpoints people can inspect, replay, debug, and hand to teammates without a 20-minute Slack explanation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; backend teams, QA workflows, auth-heavy APIs, onboarding, partner integrations, manual verification.&lt;/p&gt;

&lt;p&gt;Postman is useful because it turns one person's debugging setup into shared project knowledge. The moment auth headers, refresh flows, sample payloads, and odd edge-case requests are saved in a collection, your API stops feeling mysterious. And once those collections become something your team can rerun and share consistently, the project gets easier to trust.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://www.postman.com/" rel="noopener noreferrer"&gt;Official&lt;/a&gt; · &lt;a href="https://github.com/postmanlabs/newman" rel="noopener noreferrer"&gt;Representative repo&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/postmanlabs" rel="noopener noreferrer"&gt;
        postmanlabs
      &lt;/a&gt; / &lt;a href="https://github.com/postmanlabs/newman" rel="noopener noreferrer"&gt;
        newman
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Newman is a command-line collection runner for Postman
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a href="https://www.postman.com/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f790fa9f1bf3a99575b0fcc7f0c7a632c2454ca04c846293ee4f0858e52d6d82/68747470733a2f2f6173736574732e676574706f73746d616e2e636f6d2f636f6d6d6f6e2d73686172652f706f73746d616e2d6c6f676f2d686f72697a6f6e74616c2d333230783133322e706e67"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Manage all of your organization's APIs in Postman, with the industry's most complete API development environment.&lt;/em&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;newman &lt;em&gt;the cli companion for postman&lt;/em&gt; &lt;a href="https://github.com/postmanlabs/newman/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/postmanlabs/newman/actions/workflows/ci.yml/badge.svg?branch=develop" alt="Build Status"&gt;&lt;/a&gt; &lt;a href="https://codecov.io/gh/postmanlabs/newman" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3a4478ca4d8675017c1a3f9289d9d9fbadbc95d4be320ccc7e59bf79c69fb369/68747470733a2f2f636f6465636f762e696f2f67682f706f73746d616e6c6162732f6e65776d616e2f6272616e63682f646576656c6f702f67726170682f62616467652e737667" alt="codecov"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;Newman is a command-line collection runner for Postman. It allows you to effortlessly run and test a Postman collection directly from the command-line. It is built with extensibility in mind so that you can easily integrate it with your continuous integration servers and build systems.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Table of contents&lt;/h2&gt;
&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#getting-started" rel="noopener noreferrer"&gt;Getting Started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/postmanlabs/newman#usage" rel="noopener noreferrer"&gt;Usage&lt;/a&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#using-newman-cli" rel="noopener noreferrer"&gt;Using Newman CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#using-newman-as-a-library" rel="noopener noreferrer"&gt;Using Newman as a Library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#using-reporters-with-newman" rel="noopener noreferrer"&gt;Using Reporters with Newman&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/postmanlabs/newman#command-line-options" rel="noopener noreferrer"&gt;Command Line Options&lt;/a&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#newman-options" rel="noopener noreferrer"&gt;newman-options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#newman-run-collection-file-source-options" rel="noopener noreferrer"&gt;newman-run&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#ssl" rel="noopener noreferrer"&gt;SSL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#configuring-proxy" rel="noopener noreferrer"&gt;Configuring Proxy&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/postmanlabs/newman#api-reference" rel="noopener noreferrer"&gt;API Reference&lt;/a&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#newmanrunoptions-object--callback-function--run-eventemitter" rel="noopener noreferrer"&gt;newman run&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#newmanruncallbackerror-object--summary-object" rel="noopener noreferrer"&gt;Run summary object&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#newmanrunevents" rel="noopener noreferrer"&gt;Events emitted during a collection run&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/postmanlabs/newman#reporters" rel="noopener noreferrer"&gt;Reporters&lt;/a&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#configuring-reporters" rel="noopener noreferrer"&gt;Configuring Reporters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#cli-reporter" rel="noopener noreferrer"&gt;CLI Reporter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#json-reporter" rel="noopener noreferrer"&gt;JSON Reporter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#junitxml-reporter" rel="noopener noreferrer"&gt;JUnit Reporter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#html-reporter" rel="noopener noreferrer"&gt;HTML Reporter&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;a href="https://github.com/postmanlabs/newman#external-reporters" rel="noopener noreferrer"&gt;External Reporters&lt;/a&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#using-external-reporters" rel="noopener noreferrer"&gt;Using External Reporters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#creating-your-own-reporter" rel="noopener noreferrer"&gt;Creating Your Own Reporter&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#file-uploads" rel="noopener noreferrer"&gt;File Uploads&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#using-newman-with-the-postman-api" rel="noopener noreferrer"&gt;Using Newman with the Postman API&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#using-newman-in-docker" rel="noopener noreferrer"&gt;Using Newman in Docker&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#using-socks-proxy" rel="noopener noreferrer"&gt;Using Socks Proxy&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#migration-guide" rel="noopener noreferrer"&gt;Migration Guide&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#compatibility" rel="noopener noreferrer"&gt;Compatibility&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#contributing" rel="noopener noreferrer"&gt;Contributing&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#community-support" rel="noopener noreferrer"&gt;Community Support&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/postmanlabs/newman#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/li&gt;

&lt;/ol&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting started&lt;/h2&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/postmanlabs/newman" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  3) Docker — Kill environment roulette
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A container platform for packaging your app and its dependencies into reproducible environments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it improves your project:&lt;/strong&gt; It reduces the classic "works on my machine" tax by making local, CI, staging, and production setups much more predictable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; apps with multiple services, onboarding, backend systems, consistent local environments, reproducible deployments.&lt;/p&gt;

&lt;p&gt;Docker will not magically fix bad architecture, but it will stop the weekly ritual where one machine has the right runtime, another machine has the wrong system packages, and production is somehow "close enough." That alone makes a project calmer to ship.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Official&lt;/a&gt; · &lt;a href="https://github.com/docker/compose" rel="noopener noreferrer"&gt;Representative repo&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/docker" rel="noopener noreferrer"&gt;
        docker
      &lt;/a&gt; / &lt;a href="https://github.com/docker/compose" rel="noopener noreferrer"&gt;
        compose
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Define and run multi-container applications with Docker
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Table of Contents&lt;/h1&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/docker/compose#docker-compose" rel="noopener noreferrer"&gt;Docker Compose&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/docker/compose#where-to-get-docker-compose" rel="noopener noreferrer"&gt;Where to get Docker Compose&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/docker/compose#windows-and-macos" rel="noopener noreferrer"&gt;Windows and macOS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/docker/compose#linux" rel="noopener noreferrer"&gt;Linux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/docker/compose#quick-start" rel="noopener noreferrer"&gt;Quick Start&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/docker/compose#contributing" rel="noopener noreferrer"&gt;Contributing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/docker/compose#legacy" rel="noopener noreferrer"&gt;Legacy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Docker Compose&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/docker/compose/releases/latest" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/098ceda2418a39891f8231ac86922b9a80a56edefe4f5fe469ff1dd56748d3ff/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f646f636b65722f636f6d706f73652e7376673f7374796c653d666c61742d737175617265" alt="GitHub release"&gt;&lt;/a&gt;
&lt;a href="https://pkg.go.dev/github.com/docker/compose/v5" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b92bd49f755879826fbf8a9032e9966a79f3048d9305efd266584ea5ef6db264/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f676f2e6465762d646f63732d3030376439633f7374796c653d666c61742d737175617265266c6f676f3d676f266c6f676f436f6c6f723d7768697465" alt="PkgGoDev"&gt;&lt;/a&gt;
&lt;a href="https://github.com/docker/compose/actions?query=workflow%3Aci" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7d65ed1750bbdbbd8f7fdbf3f5e146cd5d6f96afbe74e7effbf7e1b8409ad40c/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f646f636b65722f636f6d706f73652f63692e796d6c3f6c6162656c3d6369266c6f676f3d676974687562267374796c653d666c61742d737175617265" alt="Build Status"&gt;&lt;/a&gt;
&lt;a href="https://goreportcard.com/report/github.com/docker/compose/v5" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5b314dd464f6cc1578e7fedd460b0821be018f39a915bc739d3f57bd48fe4dc5/68747470733a2f2f676f7265706f7274636172642e636f6d2f62616467652f6769746875622e636f6d2f646f636b65722f636f6d706f73652f76353f7374796c653d666c61742d737175617265" alt="Go Report Card"&gt;&lt;/a&gt;
&lt;a href="https://codecov.io/gh/docker/compose" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1efc6e6c06d2cf4ec8c2db8e3584cc771fff354a9238521feec7085832425827/68747470733a2f2f636f6465636f762e696f2f67682f646f636b65722f636f6d706f73652f6272616e63682f6d61696e2f67726170682f62616467652e7376673f746f6b656e3d4850334b345934637475" alt="Codecov"&gt;&lt;/a&gt;
&lt;a href="https://api.securityscorecards.dev/projects/github.com/docker/compose" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/cddf57aa119a0b420ad0f6dafc87b29be800eb15675327f25de7bf8b77b4a0ee/68747470733a2f2f6170692e736563757269747973636f726563617264732e6465762f70726f6a656374732f6769746875622e636f6d2f646f636b65722f636f6d706f73652f6261646765" alt="OpenSSF Scorecard"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/docker/compose/logo.png?raw=true"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fdocker%2Fcompose%2FHEAD%2Flogo.png%3Fraw%3Dtrue" alt="Docker Compose" title="Docker Compose Logo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Docker Compose is a tool for running multi-container applications on Docker
defined using the &lt;a href="https://compose-spec.io" rel="nofollow noopener noreferrer"&gt;Compose file format&lt;/a&gt;
A Compose file is used to define how one or more containers that make up
your application are configured.
Once you have a Compose file, you can create and start your application with a
single command: &lt;code&gt;docker compose up&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: About Docker Swarm
Docker Swarm used to rely on the legacy compose file format but did not adopt the compose specification
so is missing some of the recent enhancements in the compose syntax. After
&lt;a href="https://www.mirantis.com/software/swarm/" rel="nofollow noopener noreferrer"&gt;acquisition by Mirantis&lt;/a&gt; swarm isn't maintained by Docker Inc, and
as such some Docker Compose features aren't accessible to swarm users.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Where to get Docker Compose&lt;/h1&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Windows and macOS&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Docker Compose is included in
&lt;a href="https://www.docker.com/products/docker-desktop/" rel="nofollow noopener noreferrer"&gt;Docker Desktop&lt;/a&gt;…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/docker/compose" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;NODE_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;

  &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1v0so18u2gs530tznf2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1v0so18u2gs530tznf2.gif" alt="The Simpsons road trip GIF" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Trying to explain why local, staging, and production are "basically the same" when they absolutely are not. Source: &lt;a href="https://giphy.com/gifs/AnimationOnFOX-the-simpsons-road-to-cincinnati-season-32-ep-8-MsNaqI4G2rT1luIgve" rel="noopener noreferrer"&gt;The Simpsons on Giphy&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  4) Sentry — Catch the breakage before users do
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; Error tracking and performance monitoring for apps, APIs, and background jobs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it improves your project:&lt;/strong&gt; It gives failures context instead of vibes. You get stack traces, release correlation, breadcrumbs, request metadata, and performance signals that help you fix the right thing faster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; production apps, APIs, workers, frontend error tracking, release monitoring, performance debugging.&lt;/p&gt;

&lt;p&gt;Projects get better the minute production stops feeling like a blindfold. Sentry shortens the distance between "something is broken" and "here is the exact release, route, and error path that caused it."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://sentry.io/" rel="noopener noreferrer"&gt;Official&lt;/a&gt; · &lt;a href="https://github.com/getsentry/sentry" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/getsentry" rel="noopener noreferrer"&gt;
        getsentry
      &lt;/a&gt; / &lt;a href="https://github.com/getsentry/sentry" rel="noopener noreferrer"&gt;
        sentry
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Developer-first error tracking and performance monitoring
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;
    &lt;a href="https://sentry.io/?utm_source=github&amp;amp;utm_medium=logo" rel="nofollow noopener noreferrer"&gt;
      &lt;img src="https://camo.githubusercontent.com/63d7d9ecd366a58bdf965da3824d392a4ef345b8097753faa12ae07738ac8431/68747470733a2f2f73656e7472792d6272616e642e73746f726167652e676f6f676c65617069732e636f6d2f73656e7472792d776f72646d61726b2d6461726b2d3238307838342e706e67" alt="Sentry" width="280" height="84"&gt;
    &lt;/a&gt;
  &lt;/p&gt;
  &lt;p&gt;
    Users and logs provide clues. Sentry provides answers.
  &lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;What's Sentry?&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;Sentry is the debugging platform that helps every developer detect, trace, and fix issues. Code breaks, fix it faster.&lt;/p&gt;

&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/getsentry/sentry/raw/master/.github/screenshots/issue-details.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fgetsentry%2Fsentry%2Fraw%2Fmaster%2F.github%2Fscreenshots%2Fissue-details.png" width="270"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/getsentry/sentry/raw/master/.github/screenshots/seer.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fgetsentry%2Fsentry%2Fraw%2Fmaster%2F.github%2Fscreenshots%2Fseer.png" width="270"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/getsentry/sentry/raw/master/.github/screenshots/insights.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fgetsentry%2Fsentry%2Fraw%2Fmaster%2F.github%2Fscreenshots%2Finsights.png" width="270"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/getsentry/sentry/raw/master/.github/screenshots/traces.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fgetsentry%2Fsentry%2Fraw%2Fmaster%2F.github%2Fscreenshots%2Ftraces.png" width="270"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/getsentry/sentry/raw/master/.github/screenshots/trace-explorer.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fgetsentry%2Fsentry%2Fraw%2Fmaster%2F.github%2Fscreenshots%2Ftrace-explorer.png" width="270"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/getsentry/sentry/raw/master/.github/screenshots/replays.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fgetsentry%2Fsentry%2Fraw%2Fmaster%2F.github%2Fscreenshots%2Freplays.png" width="270"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/getsentry/sentry/raw/master/.github/screenshots/insights.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fgetsentry%2Fsentry%2Fraw%2Fmaster%2F.github%2Fscreenshots%2Finsights.png" width="270"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/getsentry/sentry/raw/master/.github/screenshots/logs.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fgetsentry%2Fsentry%2Fraw%2Fmaster%2F.github%2Fscreenshots%2Flogs.png" width="270"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/getsentry/sentry/raw/master/.github/screenshots/uptime.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fgetsentry%2Fsentry%2Fraw%2Fmaster%2F.github%2Fscreenshots%2Fuptime.png" width="270"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Official Sentry SDKs&lt;/h2&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry-javascript" rel="noopener noreferrer"&gt;JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry-electron/" rel="noopener noreferrer"&gt;Electron&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry-react-native" rel="noopener noreferrer"&gt;React-Native&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry-python" rel="noopener noreferrer"&gt;Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry-ruby" rel="noopener noreferrer"&gt;Ruby&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry-php" rel="noopener noreferrer"&gt;PHP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry-laravel" rel="noopener noreferrer"&gt;Laravel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry-go" rel="noopener noreferrer"&gt;Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry-rust" rel="noopener noreferrer"&gt;Rust&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry-java" rel="noopener noreferrer"&gt;Java/Kotlin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry-cocoa" rel="noopener noreferrer"&gt;Objective-C/Swift&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry-dotnet" rel="noopener noreferrer"&gt;C#/F#&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry-native" rel="noopener noreferrer"&gt;C/C++&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry-dart" rel="noopener noreferrer"&gt;Dart/Flutter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/perl-raven" rel="noopener noreferrer"&gt;Perl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry-clj/" rel="noopener noreferrer"&gt;Clojure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry-elixir" rel="noopener noreferrer"&gt;Elixir&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry-unity" rel="noopener noreferrer"&gt;Unity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry-unreal" rel="noopener noreferrer"&gt;Unreal Engine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry-godot" rel="noopener noreferrer"&gt;Godot Engine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry-powershell" rel="noopener noreferrer"&gt;PowerShell&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Resources&lt;/h1&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.sentry.io/" rel="nofollow noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/getsentry/sentry/discussions" rel="noopener noreferrer"&gt;Discussions&lt;/a&gt; (Bugs, feature requests,
general questions)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://discord.gg/PXa5Apfe7K" rel="nofollow noopener noreferrer"&gt;Discord&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.sentry.io/internal/contributing/" rel="nofollow noopener noreferrer"&gt;Contributing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry/issues" rel="noopener noreferrer"&gt;Bug Tracker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getsentry/sentry" rel="noopener noreferrer"&gt;Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://explore.transifex.com/getsentry/sentry/" rel="nofollow noopener noreferrer"&gt;Transifex&lt;/a&gt; (Translate
Sentry!)&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/getsentry/sentry" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;&lt;br&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Sentry&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@sentry/node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Sentry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;dsn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SENTRY_DSN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tracesSampleRate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  5) Playwright — Test the flows that actually make or break products
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A browser automation and end-to-end testing framework for real user journeys.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it improves your project:&lt;/strong&gt; Unit tests are great for logic. Playwright is how you protect the stuff people actually click, type, submit, and depend on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; login flows, checkout paths, onboarding, regression prevention, cross-browser testing, critical UI journeys.&lt;/p&gt;

&lt;p&gt;A lot of products feel stable right up until somebody runs the real flow. One solid Playwright test for auth, payments, or signup often prevents the kind of regression that makes a team lose confidence in every release.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://playwright.dev/" rel="noopener noreferrer"&gt;Official&lt;/a&gt; · &lt;a href="https://github.com/microsoft/playwright" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/microsoft" rel="noopener noreferrer"&gt;
        microsoft
      &lt;/a&gt; / &lt;a href="https://github.com/microsoft/playwright" rel="noopener noreferrer"&gt;
        playwright
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Playwright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API. 
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🎭 Playwright&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/playwright" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0c0b88b731baae15c1fea7318541bac85741ecce8999effb24c9ef0424c90a9c/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f706c61797772696768742e737667" alt="npm version"&gt;&lt;/a&gt; &lt;a href="https://www.chromium.org/Home" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3bc87c4989cdbc340aee9d64f0afee6e0fea831220dd2832b2b1f09e3d33f6b0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6368726f6d69756d2d3134372e302e373732372e34392d626c75652e7376673f6c6f676f3d676f6f676c652d6368726f6d65" alt="Chromium version"&gt;&lt;/a&gt; &lt;a href="https://www.mozilla.org/en-US/firefox/new/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7a08142d1731126e65ef4aba60edf37271ad1cec4c693ead952639015ac968cd/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f66697265666f782d3134382e302e322d626c75652e7376673f6c6f676f3d66697265666f7862726f77736572" alt="Firefox version"&gt;&lt;/a&gt; &lt;a href="https://webkit.org/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5c900e8803765a59d9436251138d1ffc21f224465c01ba5a22cf5ebca96ea992/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7765626b69742d32362e342d626c75652e7376673f6c6f676f3d736166617269" alt="WebKit version"&gt;&lt;/a&gt; &lt;a href="https://aka.ms/playwright/discord" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a0f278c5bb9bf1c04af523df174c2526d259f8441df73f3378f686863c9ffde0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6a6f696e2d646973636f72642d696e666f726d6174696f6e616c" alt="Join Discord"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;
&lt;a href="https://playwright.dev" rel="nofollow noopener noreferrer"&gt;Documentation&lt;/a&gt; | &lt;a href="https://playwright.dev/docs/api/class-playwright" rel="nofollow noopener noreferrer"&gt;API reference&lt;/a&gt;
&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Playwright is a framework for web automation and testing. It drives Chromium, Firefox, and WebKit with a single API — in your tests, in your scripts, and as a tool for AI agents.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Get Started&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Choose the path that fits your workflow:&lt;/p&gt;

&lt;p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;br&gt;
&lt;thead&gt;
&lt;br&gt;
&lt;tr&gt;


&lt;th&gt;Best for&lt;/th&gt;
&lt;br&gt;
&lt;th&gt;Install&lt;/th&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/thead&gt;
&lt;br&gt;
&lt;tbody&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://github.com/microsoft/playwright#playwright-test" rel="noopener noreferrer"&gt;Playwright Test&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;End-to-end testing&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;npm init playwright@latest&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://github.com/microsoft/playwright#playwright-cli" rel="noopener noreferrer"&gt;Playwright CLI&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Coding agents (Claude Code, Copilot)&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;npm i -g @playwright/cli@latest&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://github.com/microsoft/playwright#playwright-mcp" rel="noopener noreferrer"&gt;Playwright MCP&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;AI agents and LLM-driven automation&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;npx @playwright/mcp@latest&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://github.com/microsoft/playwright#playwright-library" rel="noopener noreferrer"&gt;Playwright Library&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Browser automation scripts&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;npm i playwright&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href="https://github.com/microsoft/playwright#vs-code-extension" rel="noopener noreferrer"&gt;VS Code Extension&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Test authoring and debugging in VS Code&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-playwright.playwright" rel="nofollow noopener noreferrer"&gt;Install from Marketplace&lt;/a&gt;&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/tbody&gt;
&lt;br&gt;
&lt;/table&gt;&lt;/div&gt;&lt;br&gt;
&lt;/p&gt;


&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Playwright Test&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;Playwright Test is a full-featured test runner built for end-to-end testing. It runs tests across Chromium, Firefox, and WebKit with full browser isolation, auto-waiting, and web-first assertions.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Install&lt;/h3&gt;

&lt;/div&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm init playwright@latest&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Or add manually:&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm i -D @playwright/test
npx playwright install&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Write a test&lt;/h3&gt;

&lt;/div&gt;

&lt;div class="highlight highlight-source-ts notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-s1"&gt;test&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;expect&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/microsoft/playwright" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@playwright/test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checkout completes successfully&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/checkout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByLabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dev@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Pay now&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Payment confirmed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBeVisible&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fytknrcugcpceeb9l9wbj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fytknrcugcpceeb9l9wbj.gif" alt="South Park developers staring at screens" width="384" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The exact moment your one "probably fine" user flow turns out to be the one thing that definitely needed an end-to-end test. Source: &lt;a href="https://giphy.com/gifs/southparkgifs-l3vRd3vZPrApPqzjq" rel="noopener noreferrer"&gt;South Park on Giphy&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  6) Swagger / OpenAPI — Turn your API into a real contract
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A specification-driven way to describe routes, payloads, auth requirements, and responses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it improves your project:&lt;/strong&gt; It makes your API explicit. That means better docs, fewer frontend/backend misunderstandings, easier integrations, and less behavior hidden in memory or tribal knowledge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; internal APIs, public APIs, SDK generation, backend teams, frontend handoff, partner integrations.&lt;/p&gt;

&lt;p&gt;When the contract is written down, fewer things depend on guessing. That helps new teammates onboard faster, frontend work unblock earlier, and backend changes stop surprising everybody else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://www.openapis.org/" rel="noopener noreferrer"&gt;Official spec&lt;/a&gt; · &lt;a href="https://swagger.io/swagger-ui/" rel="noopener noreferrer"&gt;Swagger UI&lt;/a&gt; · &lt;a href="https://github.com/swagger-api/swagger-ui" rel="noopener noreferrer"&gt;Representative repo&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/swagger-api" rel="noopener noreferrer"&gt;
        swagger-api
      &lt;/a&gt; / &lt;a href="https://github.com/swagger-api/swagger-ui" rel="noopener noreferrer"&gt;
        swagger-ui
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Swagger UI is a collection of HTML, JavaScript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;&lt;a rel="noopener noreferrer nofollow" href="https://raw.githubusercontent.com/swagger-api/swagger.io/wordpress/images/assets/SWU-logo-clr.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fswagger-api%2Fswagger.io%2Fwordpress%2Fimages%2Fassets%2FSWU-logo-clr.png" width="300"&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="http://badge.fury.io/js/swagger-ui" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/cfe28814e1caf20cbfa822bdd725f8ba712d06c6fb0255158ef957e1a85d0300/68747470733a2f2f62616467652e667572792e696f2f6a732f737761676765722d75692e737667" alt="NPM version"&gt;&lt;/a&gt;
&lt;a href="https://jenkins.swagger.io/view/OSS%20-%20JavaScript/job/oss-swagger-ui-master/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/20fa9ff4b88dd6e8ee2952e4736b530ecb6eb97a09aa74e7f7730f0c15e2a820/68747470733a2f2f6a656e6b696e732e737761676765722e696f2f766965772f4f53532532302d2532304a6176615363726970742f6a6f622f6f73732d737761676765722d75692d6d61737465722f62616467652f69636f6e3f7375626a6563743d6a656e6b696e732532306275696c64" alt="Build Status"&gt;&lt;/a&gt;
&lt;a href="https://jenkins.swagger.io/job/oss-swagger-ui-security-audit/lastBuild/console" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e323b81c6ca5c63dd835bb6095f8f2a46669c4d1194ee9768a525a32d69e5ef0/68747470733a2f2f6a656e6b696e732e737761676765722e696f2f6275696c645374617475732f69636f6e3f6a6f623d6f73732d737761676765722d75692d73656375726974792d6175646974267375626a6563743d6e706d2532306175646974" alt="npm audit"&gt;&lt;/a&gt;
&lt;a href="https://github.com/swagger-api/swagger-ui/graphs/contributors" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/cdde3d9c89070c961c862fbbc92cfa497ada3a3a9a427279326b7cc2af316c20/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f636f6e7472696275746f72732d616e6f6e2f737761676765722d6170692f737761676765722d75692e737667" alt="total GitHub contributors"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.npmjs.com/package/swagger-ui" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a74195c108b9895617dab4ffc4c3cc4f75aaa00dbd9ad24c2f68777c6616a912/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f646d2f737761676765722d75692e7376673f6c6162656c3d6e706d253230646f776e6c6f616473" alt="monthly npm installs"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/93a4b0cdd6b10e98d88f41fc4bd5583dafc95616232039f049238dfbc654439b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646f636b65722d646f636b65722e737761676765722e696f25324673776167676572617069253246737761676765722d2d75692d626c7565"&gt;&lt;img src="https://camo.githubusercontent.com/93a4b0cdd6b10e98d88f41fc4bd5583dafc95616232039f049238dfbc654439b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646f636b65722d646f636b65722e737761676765722e696f25324673776167676572617069253246737761676765722d2d75692d626c7565" alt="docker registry"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/19d9515165e5ccfc77c6f003b6f55732d408a1933cbadc95b11f79d0239152c3/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646d2f737761676765722d6170692f737761676765722d75692e7376673f6c6162656c3d7061636b6167697374253230696e7374616c6c73"&gt;&lt;img src="https://camo.githubusercontent.com/19d9515165e5ccfc77c6f003b6f55732d408a1933cbadc95b11f79d0239152c3/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646d2f737761676765722d6170692f737761676765722d75692e7376673f6c6162656c3d7061636b6167697374253230696e7374616c6c73" alt="monthly packagist installs"&gt;&lt;/a&gt;
&lt;a href="https://bundlephobia.com/package/swagger-ui" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7ee0491b66dddf6f7b7676ce1a50c68a236319b4079f63fc88493ad37087300e/68747470733a2f2f696d672e736869656c64732e696f2f62756e646c6570686f6269612f6d696e7a69702f737761676765722d75692e7376673f6c6162656c3d677a697025323073697a65" alt="gzip size"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Introduction&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://swagger.io/tools/swagger-ui/" rel="nofollow noopener noreferrer"&gt;Swagger UI&lt;/a&gt; allows anyone — be it your development team or your end consumers — to visualize and interact with the API’s resources without having any of the implementation logic in place. It’s automatically generated from your OpenAPI (formerly known as Swagger) Specification, with the visual documentation making it easy for back end implementation and client side consumption.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;General&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;👉🏼 Want to score an easy open-source contribution?&lt;/strong&gt; Check out our &lt;a href="https://github.com/swagger-api/swagger-ui/issues?q=is%3Aissue+is%3Aopen+label%3A%22Good+first+issue%22" rel="noopener noreferrer"&gt;Good first issue&lt;/a&gt; label.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;🕰️ Looking for the older version of Swagger UI?&lt;/strong&gt; Refer to the &lt;a href="https://github.com/swagger-api/swagger-ui/tree/2.x" rel="noopener noreferrer"&gt;&lt;em&gt;2.x&lt;/em&gt; branch&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This repository publishes three different NPM modules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/swagger-ui" rel="nofollow noopener noreferrer"&gt;swagger-ui&lt;/a&gt; is a traditional npm module intended for use in single-page applications that are capable of resolving dependencies (via Webpack, Browserify, etc.).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/swagger-ui-dist" rel="nofollow noopener noreferrer"&gt;swagger-ui-dist&lt;/a&gt; is a dependency-free module that includes everything you need to serve Swagger UI in a server-side project, or a single-page application that can't resolve npm module dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/swagger-ui-react" rel="nofollow noopener noreferrer"&gt;swagger-ui-react&lt;/a&gt; is Swagger…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/swagger-api/swagger-ui" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;openapi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3.1.0&lt;/span&gt;
&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Example&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;API"&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.0.0&lt;/span&gt;
&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;/users/{id}&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Fetch a user&lt;/span&gt;
      &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;path&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
      &lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;200"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;returned&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;successfully"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1v0so18u2gs530tznf2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1v0so18u2gs530tznf2.gif" alt="The Simpsons road trip GIF" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Frontend, backend, and QA when the API shape is finally written down in one place instead of floating around in chat history. Source: &lt;a href="https://giphy.com/gifs/AnimationOnFOX-the-simpsons-road-to-cincinnati-season-32-ep-8-MsNaqI4G2rT1luIgve" rel="noopener noreferrer"&gt;The Simpsons on Giphy&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  7) pompelmi — Secure the upload edge before it bites you
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A Node.js file upload security tool that scans uploads in-process before you accept them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it improves your project:&lt;/strong&gt; Upload handling is one of the most underestimated attack surfaces in web apps. Extensions lie, MIME types can be spoofed, archives can be risky, and "we'll validate later" is how tiny assumptions become expensive incidents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; Express, Fastify, Koa, NestJS, Next.js, privacy-sensitive products, public upload flows, moderation-heavy apps.&lt;/p&gt;

&lt;p&gt;Most teams spend more time styling the upload button than defending the upload pipeline. That is backwards. A tool like &lt;a href="https://github.com/pompelmi/pompelmi" rel="noopener noreferrer"&gt;pompelmi&lt;/a&gt; helps you make verdict-based decisions before a file becomes your problem, which is exactly the kind of boring guardrail mature projects quietly rely on.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/pompelmi/pompelmi" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Site: &lt;a href="https://pompelmi.github.io/pompelmi/" rel="noopener noreferrer"&gt;Project site&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Demo: &lt;a href="https://pompelmi.github.io/pompelmi/demo/?ref=producthunt" rel="noopener noreferrer"&gt;Live demo&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;scanBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;STRICT_PUBLIC_UPLOAD&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pompelmi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scanBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;mimeType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mimetype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;STRICT_PUBLIC_UPLOAD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;failClosed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;verdict&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;clean&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;422&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Upload blocked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;verdict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;verdict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If you handle user uploads in Node.js, this is the kind of layer that makes your project feel much more intentional. It is not just about malware. It is about treating MIME spoofing, risky archives, and uncertain files as security decisions instead of wishful thinking.&lt;/p&gt;
&lt;h3&gt;
  
  
  Repository preview
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftpta32fr1ijb956g7es6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftpta32fr1ijb956g7es6.png" alt="pompelmi repository banner" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/pompelmi" rel="noopener noreferrer"&gt;
        pompelmi
      &lt;/a&gt; / &lt;a href="https://github.com/pompelmi/pompelmi" rel="noopener noreferrer"&gt;
        pompelmi
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Open-source file upload security for Node.js. Scan files before storage to detect malware, MIME spoofing, and risky archives.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Pompelmi&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;In-process file upload security for Node.js. Inspect untrusted files before storage so your application can reject, quarantine, or accept with context.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/pompelmi" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e0d42981d2ee0a7922681b51f292837bf13d14622e6e08fdb9ab6a10c0e01c8b/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f706f6d70656c6d69" alt="npm version"&gt;&lt;/a&gt;
&lt;a href="https://github.com/pompelmi/pompelmi/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/88fcc5ec40e69b2f99fc5b711e2d11e121c009bbd7e34320be41a01ec6df9023/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f706f6d70656c6d692f706f6d70656c6d692f63692e796d6c3f6c6162656c3d6369" alt="CI"&gt;&lt;/a&gt;
&lt;a href="https://github.com/pompelmi/pompelmi/stargazers" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0c7b5fc13dd2baf14b42b2c762318188faec8b92a0f0e39b3d5f937cc1072532/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f73746172732f706f6d70656c6d692f706f6d70656c6d69" alt="GitHub stars"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Pompelmi helps reduce:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MIME / extension spoofing and magic-byte mismatches&lt;/li&gt;
&lt;li&gt;risky archive structures such as ZIP bombs, traversal, and deep nesting&lt;/li&gt;
&lt;li&gt;risky document and binary patterns such as PDF actions, Office macro hints, PE signatures, and polyglot files&lt;/li&gt;
&lt;li&gt;store-first upload flows that need a clean / suspicious / malicious verdict before persistence&lt;/li&gt;
&lt;li&gt;known malicious matches when you plug in YARA or another scanner&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Install: &lt;code&gt;npm install pompelmi&lt;/code&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quick Start&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-ts notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-s1"&gt;scanBytes&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c1"&gt;STRICT_PUBLIC_UPLOAD&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s"&gt;'pompelmi'&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;report&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;await&lt;/span&gt; &lt;span class="pl-en"&gt;scanBytes&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;file&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;buffer&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-c1"&gt;filename&lt;/span&gt;: &lt;span class="pl-s1"&gt;file&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;originalname&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-c1"&gt;mimeType&lt;/span&gt;: &lt;span class="pl-s1"&gt;file&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;mimetype&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-c1"&gt;policy&lt;/span&gt;: &lt;span class="pl-c1"&gt;STRICT_PUBLIC_UPLOAD&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
  &lt;span class="pl-c1"&gt;failClosed&lt;/span&gt;: &lt;span class="pl-c1"&gt;true&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-k"&gt;if&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;report&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;verdict&lt;/span&gt; &lt;span class="pl-c1"&gt;!==&lt;/span&gt; &lt;span class="pl-s"&gt;'clean'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-s1"&gt;res&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;status&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-c1"&gt;422&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/pompelmi/pompelmi" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flb1s195cp236p7ihx18a.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flb1s195cp236p7ihx18a.gif" alt="pompelmi malware detection demo" width="600" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Upload security usually feels optional right until it really, really is not.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  8) Dependabot — Keep dependency drift from turning into real risk
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; GitHub's automated dependency update system for packages, containers, and workflow versions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it improves your project:&lt;/strong&gt; It keeps security and maintenance work moving in small increments instead of one painful cleanup sprint after months of neglect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; npm repos, Docker images, GitHub Actions workflows, libraries, apps with busy dependency trees.&lt;/p&gt;

&lt;p&gt;Most dependency risk is boring right until it is suddenly not. Dependabot makes updates reviewable, visible, and routine, which is much better than discovering six months of drift during an incident or release crunch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://docs.github.com/github/administering-a-repository/about-github-dependabot" rel="noopener noreferrer"&gt;Docs&lt;/a&gt; · &lt;a href="https://github.com/dependabot/dependabot-core" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/dependabot" rel="noopener noreferrer"&gt;
        dependabot
      &lt;/a&gt; / &lt;a href="https://github.com/dependabot/dependabot-core" rel="noopener noreferrer"&gt;
        dependabot-core
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      🤖 Dependabot's core logic for creating update PRs.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;
    
        
        
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F7659%2F174594540-5e29e523-396a-465b-9a6e-6cab5b15a568.svg" alt="Dependabot" width="336"&gt;
    
&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Welcome to the public home of Dependabot &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.githubassets.com%2Fimages%2Ficons%2Femoji%2Fdependabot.png" class="article-body-image-wrapper"&gt;&lt;img class="emoji" title=":dependabot:" alt=":dependabot:" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.githubassets.com%2Fimages%2Ficons%2Femoji%2Fdependabot.png" height="20" width="20"&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Table of Contents&lt;/h1&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/dependabot/dependabot-core#what-is-dependabot-core" rel="noopener noreferrer"&gt;What is Dependabot-Core?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dependabot/dependabot-core#how-to-run-dependabot" rel="noopener noreferrer"&gt;How to run Dependabot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/dependabot/dependabot-core#contributing-to-dependabot" rel="noopener noreferrer"&gt;Contributing to Dependabot&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/dependabot/dependabot-core#reporting-issues-and-feature-requests" rel="noopener noreferrer"&gt;Reporting Issues and Feature Requests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dependabot/dependabot-core#submitting-pull-requests" rel="noopener noreferrer"&gt;Submitting Pull Requests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dependabot/dependabot-core#new-ecosystems" rel="noopener noreferrer"&gt;New Ecosystems&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/dependabot/dependabot-core#development-guide" rel="noopener noreferrer"&gt;Development Guide&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/dependabot/dependabot-core#getting-a-development-environment-running" rel="noopener noreferrer"&gt;Getting a Development Environment Running&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dependabot/dependabot-core#debugging-problems" rel="noopener noreferrer"&gt;Debugging Problems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dependabot/dependabot-core#running-tests" rel="noopener noreferrer"&gt;Running Tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dependabot/dependabot-core#profiling" rel="noopener noreferrer"&gt;Profiling&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dependabot/dependabot-core#architecture-and-code-layout" rel="noopener noreferrer"&gt;Architecture and Code Layout&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dependabot/dependabot-core#trademarks" rel="noopener noreferrer"&gt;Trademarks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dependabot/dependabot-core#notes-for-project-maintainers" rel="noopener noreferrer"&gt;Notes for Project Maintainers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;What is Dependabot-Core?&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Dependabot-Core is the library at the heart of &lt;a href="https://docs.github.com/en/code-security/dependabot" rel="noopener noreferrer"&gt;Dependabot&lt;/a&gt; security / version updates.&lt;/p&gt;
&lt;p&gt;Use it to generate automated pull requests updating dependencies for projects written in Ruby, JavaScript, Python,
PHP, Dart, Elixir, Elm, Go, Rust, Java, Julia, and .NET. It can also update git submodules, Docker files, Opentofu, Terraform files and Pre-Commit hooks.
Features include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Check for the latest version of a dependency &lt;em&gt;that's resolvable given a project's other dependencies&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Generate updated manifest and lockfiles for a new dependency version&lt;/li&gt;
&lt;li&gt;Generate PR descriptions that include the updated dependency's changelogs, release notes, and commits&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;How to&lt;/h1&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/dependabot/dependabot-core" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;span class="na"&gt;updates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;package-ecosystem&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm&lt;/span&gt;
    &lt;span class="na"&gt;directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
    &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;weekly&lt;/span&gt;
    &lt;span class="na"&gt;open-pull-requests-limit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;package-ecosystem&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github-actions&lt;/span&gt;
    &lt;span class="na"&gt;directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
    &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;weekly&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxknr34f6np28h96a1kx.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxknr34f6np28h96a1kx.gif" alt="Family Guy shocked at the computer" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The face you make when a stale dependency turns into tonight's emergency patch window. Source: &lt;a href="https://giphy.com/gifs/fox-computer-family-guy-5nvQ7fBWhPVXXOcfRI" rel="noopener noreferrer"&gt;Family Guy on Giphy&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  9) Excalidraw — Think clearly before you build expensively
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A fast, low-friction whiteboard for architecture sketches, flows, states, and system diagrams.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it improves your project:&lt;/strong&gt; It helps teams see the system before they commit to the system. That reduces misalignment, hand-wavy assumptions, and long explanations nobody remembers later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; architecture reviews, sequence diagrams, onboarding docs, RFCs, async collaboration, state-flow discussions.&lt;/p&gt;

&lt;p&gt;A five-minute sketch can save hours of wrong implementation. Excalidraw is especially good when a project keeps getting explained verbally but never gets turned into something the whole team can point at and improve together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://excalidraw.com/" rel="noopener noreferrer"&gt;Official&lt;/a&gt; · &lt;a href="https://github.com/excalidraw/excalidraw" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/excalidraw" rel="noopener noreferrer"&gt;
        excalidraw
      &lt;/a&gt; / &lt;a href="https://github.com/excalidraw/excalidraw" rel="noopener noreferrer"&gt;
        excalidraw
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Virtual whiteboard for sketching hand-drawn like diagrams
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;a href="https://excalidraw.com/" rel="nofollow noopener noreferrer"&gt;
  
    
    &lt;img alt="Excalidraw" src="https://camo.githubusercontent.com/998e67de729ddc7a96857f3ad11075481ee1ea59e6c5e79c6b13886013cce97b/68747470733a2f2f657863616c69647261772e6e7963332e63646e2e6469676974616c6f6365616e7370616365732e636f6d2f6769746875622f657863616c69647261775f6769746875625f636f7665725f322e706e67"&gt;
  
&lt;/a&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;
  &lt;a href="https://excalidraw.com" rel="nofollow noopener noreferrer"&gt;Excalidraw Editor&lt;/a&gt; |
  &lt;a href="https://plus.excalidraw.com/blog" rel="nofollow noopener noreferrer"&gt;Blog&lt;/a&gt; |
  &lt;a href="https://docs.excalidraw.com" rel="nofollow noopener noreferrer"&gt;Documentation&lt;/a&gt; |
  &lt;a href="https://plus.excalidraw.com" rel="nofollow noopener noreferrer"&gt;Excalidraw+&lt;/a&gt;
&lt;/h4&gt;
&lt;/div&gt;

&lt;div&gt;
  &lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;
    An open source virtual hand-drawn style whiteboard. &lt;br&gt;
    Collaborative and end-to-end encrypted. &lt;br&gt;
  &lt;br&gt;
  &lt;/h2&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;

&lt;p&gt;
  &lt;a href="https://github.com/excalidraw/excalidraw/blob/master/LICENSE" rel="noopener noreferrer"&gt;
    &lt;img alt="Excalidraw is released under the MIT license." src="https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667"&gt;&lt;/a&gt;
  &lt;a href="https://www.npmjs.com/package/@excalidraw/excalidraw" rel="nofollow noopener noreferrer"&gt;
    &lt;img alt="npm downloads/month" src="https://camo.githubusercontent.com/b888038a3f43d195f22378d9e805a780cf8ae92b3a21170cf3b9a6d49b646c90/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f646d2f40657863616c69647261772f657863616c6964726177"&gt;&lt;/a&gt;
  &lt;a href="https://docs.excalidraw.com/docs/introduction/contributing" rel="nofollow noopener noreferrer"&gt;
    &lt;img alt="PRs welcome!" src="https://camo.githubusercontent.com/7d9ed3c8f22eceb1711573169b1390cc0b1194467340dc815205060c162b5309/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5052732d77656c636f6d652d627269676874677265656e2e7376673f7374796c653d666c6174"&gt;&lt;/a&gt;
  &lt;a href="https://discord.gg/UexuTaE" rel="nofollow noopener noreferrer"&gt;
    &lt;img alt="Chat on Discord" src="https://camo.githubusercontent.com/bd5521032bc04de0884f38454e796fc9841b675ed8b713960f3ad8fa1912ffc9/68747470733a2f2f696d672e736869656c64732e696f2f646973636f72642f3732333637323433303734343137343638323f636f6c6f723d373338616436266c6162656c3d436861742532306f6e253230446973636f7264266c6f676f3d646973636f7264266c6f676f436f6c6f723d666666666666267769646765743d66616c7365"&gt;&lt;/a&gt;
  &lt;a href="https://deepwiki.com/excalidraw/excalidraw" rel="nofollow noopener noreferrer"&gt;
    &lt;img alt="Ask DeepWiki" src="https://camo.githubusercontent.com/0f5ae213ac378635adeb5d7f13cef055ad2f7d9a47b36de7b1c67dbe09f609ca/68747470733a2f2f6465657077696b692e636f6d2f62616467652e737667"&gt;&lt;/a&gt;
  &lt;a href="https://twitter.com/excalidraw" rel="nofollow noopener noreferrer"&gt;
    &lt;img alt="Follow Excalidraw on Twitter" src="https://camo.githubusercontent.com/601234ddc1c94ae90113c962cbae8f570910de0a8706705d1a27897cd74e47ad/68747470733a2f2f696d672e736869656c64732e696f2f747769747465722f666f6c6c6f772f657863616c69647261772e7376673f6c6162656c3d666f6c6c6f772b40657863616c6964726177267374796c653d736f6369616c266c6f676f3d74776974746572"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;div&gt;
    &lt;a href="https://excalidraw.com" rel="nofollow noopener noreferrer"&gt;
      &lt;img src="https://camo.githubusercontent.com/1be1106db66a9fbbe2a19cc027266ff647ecb7269d542e0712ff36d4a25c294a/68747470733a2f2f657863616c69647261772e6e7963332e63646e2e6469676974616c6f6365616e7370616365732e636f6d2f67697468756225324670726f647563745f73686f77636173652e706e67" alt="Product showcase"&gt;
    &lt;/a&gt;
    
      &lt;p&gt;
        Create beautiful hand-drawn like diagrams, wireframes, or whatever you like.
      &lt;/p&gt;
    
  
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;The Excalidraw editor (npm package) supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💯 Free &amp;amp; open-source.&lt;/li&gt;
&lt;li&gt;🎨 Infinite, canvas-based whiteboard.&lt;/li&gt;
&lt;li&gt;✍️ Hand-drawn like style.&lt;/li&gt;
&lt;li&gt;🌓 Dark mode.&lt;/li&gt;
&lt;li&gt;🏗️ Customizable.&lt;/li&gt;
&lt;li&gt;📷 Image support.&lt;/li&gt;
&lt;li&gt;😀 Shape libraries support.&lt;/li&gt;
&lt;li&gt;🌐 Localization (i18n) support.&lt;/li&gt;
&lt;li&gt;🖼️ Export to PNG, SVG &amp;amp; clipboard.&lt;/li&gt;
&lt;li&gt;💾 Open format - export drawings as an &lt;code&gt;.excalidraw&lt;/code&gt; json file.&lt;/li&gt;
&lt;li&gt;⚒️ Wide range of tools - rectangle, circle, diamond, arrow, line, free-draw, eraser...&lt;/li&gt;
&lt;li&gt;➡️ Arrow-binding &amp;amp; labeled arrows.&lt;/li&gt;
&lt;li&gt;🔙 Undo / Redo.&lt;/li&gt;
&lt;li&gt;🔍 Zoom and panning support.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Excalidraw.com&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;The app hosted at &lt;a href="https://excalidraw.com" rel="nofollow noopener noreferrer"&gt;excalidraw.com&lt;/a&gt; is a minimal showcase of what you can build with Excalidraw. Its &lt;a href="https://github.com/excalidraw/excalidraw/tree/master/excalidraw-app" rel="noopener noreferrer"&gt;source code&lt;/a&gt; is part of this repository as well, and the app features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📡 PWA support (works offline).&lt;/li&gt;
&lt;li&gt;🤼 Real-time collaboration.&lt;/li&gt;
&lt;li&gt;🔒 End-to-end…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/excalidraw/excalidraw" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2&gt;
  
  
  10) Raycast — Remove friction from the machine itself
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; A keyboard-first launcher and automation layer for local developer workflows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it improves your project:&lt;/strong&gt; Not every project improvement lives in the repo. Faster local execution means less context-switching, fewer tiny interruptions, and more energy left for the work that actually matters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for:&lt;/strong&gt; macOS-based developers, snippets, quick scripts, search, clipboard workflows, window control, micro-automation.&lt;/p&gt;

&lt;p&gt;Raycast is one of those tools that quietly improves everything around your coding day. Opening the right folders, jumping to tickets, searching docs, running snippets, and triggering scripts faster sounds small until you notice how much time you stop wasting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://raycast.com/" rel="noopener noreferrer"&gt;Official&lt;/a&gt; · &lt;a href="https://github.com/raycast/extensions" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/raycast" rel="noopener noreferrer"&gt;
        raycast
      &lt;/a&gt; / &lt;a href="https://github.com/raycast/extensions" rel="noopener noreferrer"&gt;
        extensions
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Everything you need to extend Raycast.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/raycast/extensions/images/store-logo.webp"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraycast%2Fextensions%2FHEAD%2Fimages%2Fstore-logo.webp" height="128"&gt;&lt;/a&gt;
  &lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Raycast Extensions&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;
  &lt;a href="https://x.com/raycast" rel="nofollow noopener noreferrer"&gt;
    &lt;img alt="" src="https://camo.githubusercontent.com/c504b2ad6f5cac0a3da902b380b8b837a9c277b95d9a78717e6ae4c9466531b0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466f6c6c6f7725323040726179636173742d626c61636b2e7376673f7374796c653d666f722d7468652d6261646765266c6f676f3d58"&gt;
  &lt;/a&gt;
  &lt;a href="https://raycast.com/community" rel="nofollow noopener noreferrer"&gt;
    &lt;img alt="" src="https://camo.githubusercontent.com/4c6a01363e9db745bfd386e358718acc9ad706ce2511e16ea6328db7228aa58a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4a6f696e253230746865253230636f6d6d756e6974792d626c61636b2e7376673f7374796c653d666f722d7468652d6261646765266c6f676f3d52617963617374266c6f676f436f6c6f723d666666"&gt;
  &lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href="https://raycast.com/" rel="nofollow noopener noreferrer"&gt;Raycast&lt;/a&gt; lets you control your tools with a few keystrokes. This repository contains all extensions that are available in the &lt;a href="https://raycast.com/store" rel="nofollow noopener noreferrer"&gt;Raycast Store&lt;/a&gt;. It also includes documentation and examples of how to extend Raycast using React.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/raycast/extensions/images/header.webp"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fraycast%2Fextensions%2FHEAD%2Fimages%2Fheader.webp" alt="Header"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting Started&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Visit &lt;a href="https://developers.raycast.com" rel="nofollow noopener noreferrer"&gt;https://developers.raycast.com&lt;/a&gt; to get started with our API. If you want to discover and install extensions, check out &lt;a href="https://raycast.com/store" rel="nofollow noopener noreferrer"&gt;our Store&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Be sure to read and follow our &lt;a href="https://manual.raycast.com/community-guidelines" rel="nofollow noopener noreferrer"&gt;Community&lt;/a&gt; and &lt;a href="https://manual.raycast.com/extensions" rel="nofollow noopener noreferrer"&gt;Extension&lt;/a&gt; guidelines and &lt;a href="https://www.raycast.com/aup" rel="nofollow noopener noreferrer"&gt;Acceptable Use Policy&lt;/a&gt; when submitting your extension and interacting with other folks in this repository.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Feedback&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Raycast wouldn't be where it is without the feedback from our community, so we would be happy to hear what you think of the API / DevX and how we can improve. Please use &lt;a href="https://github.com/raycast/extensions/issues/new/choose" rel="noopener noreferrer"&gt;GitHub issues&lt;/a&gt; for everything API related (bugs, improvements suggestions, developer experience, docs, etc). We have a few &lt;a href="https://developers.raycast.com/examples" rel="nofollow noopener noreferrer"&gt;templates&lt;/a&gt; that should help you get started.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Community&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Join our…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/raycast/extensions" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fytknrcugcpceeb9l9wbj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fytknrcugcpceeb9l9wbj.gif" alt="South Park developers staring at computer screens" width="384" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What your laptop sees after you finally replace ten tiny daily interruptions with one keyboard-first workflow. Source: &lt;a href="https://giphy.com/gifs/southparkgifs-l3vRd3vZPrApPqzjq" rel="noopener noreferrer"&gt;South Park on Giphy&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;The projects people trust are rarely the ones with the flashiest feature list.&lt;/p&gt;

&lt;p&gt;They are the ones where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deploys are repeatable&lt;/li&gt;
&lt;li&gt;APIs are easy to test&lt;/li&gt;
&lt;li&gt;user flows are protected&lt;/li&gt;
&lt;li&gt;production failures are visible&lt;/li&gt;
&lt;li&gt;docs are explicit&lt;/li&gt;
&lt;li&gt;uploads are treated like a real security boundary&lt;/li&gt;
&lt;li&gt;dependencies do not rot quietly&lt;/li&gt;
&lt;li&gt;ideas are clarified before code gets expensive&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is why good tooling matters so much.&lt;/p&gt;

&lt;p&gt;It does not just make developers faster.&lt;br&gt;
It makes projects better.&lt;/p&gt;

&lt;p&gt;If you could add only one of these to your stack this week, which one would make the biggest difference?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
      <category>devops</category>
    </item>
    <item>
      <title>7 Real Workflows That Actually Save Developers Hours</title>
      <dc:creator>Tommaso Bertocchi</dc:creator>
      <pubDate>Thu, 02 Apr 2026 13:50:09 +0000</pubDate>
      <link>https://dev.to/sonotommy/7-real-workflows-that-actually-save-developers-hours-5550</link>
      <guid>https://dev.to/sonotommy/7-real-workflows-that-actually-save-developers-hours-5550</guid>
      <description>&lt;p&gt;Most developers are still using AI like a novelty keyboard shortcut.&lt;/p&gt;

&lt;p&gt;They ask it for regexes, toy apps, or random refactors, then wonder why the payoff feels small.&lt;/p&gt;

&lt;p&gt;That is the wrong mental model.&lt;/p&gt;

&lt;p&gt;The real value is not "write code for me." The real value is "remove the friction around engineering work."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmm44wl288uhglzor382a.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmm44wl288uhglzor382a.gif" alt="Developer typing hard at a home workstation" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;GIF source: &lt;a href="https://giphy.com/gifs/salesforce-bear-computer-work-from-home-1GEATImIxEXVR79Dhk" rel="noopener noreferrer"&gt;Salesforce on Giphy&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The code itself is often not the slow part. The slow part is turning messy human input into something the codebase can actually absorb.&lt;/p&gt;

&lt;p&gt;Bug reports are vague. Product requests are fuzzy. PRs hide edge cases. Logs are noisy. Meetings are chaos. Docs get written last. Migrations start with "should be fine" and end with regret.&lt;/p&gt;

&lt;p&gt;That is where AI earns its keep.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Stop using AI for one-off tricks and start using it for repeatable engineering workflows.&lt;/li&gt;
&lt;li&gt;The best workflows sit before coding or after coding, not just inside the editor.&lt;/li&gt;
&lt;li&gt;AI is great at turning messy input into structured output.&lt;/li&gt;
&lt;li&gt;Good outputs include test cases, checklists, review notes, implementation plans, and docs.&lt;/li&gt;
&lt;li&gt;You still own the judgment.&lt;/li&gt;
&lt;li&gt;You let the model handle the formatting, sorting, summarizing, and first-pass synthesis.&lt;/li&gt;
&lt;li&gt;AI stops feeling like a toy when it becomes part of your process.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
AI stops being impressive when you demo it.

&lt;p&gt;It starts being useful when it handles the annoying parts of engineering.&lt;br&gt;

&lt;/p&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  1. Turn rough bug reports into reproducible test cases
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; most bug reports are written like crime scene poetry.&lt;/p&gt;

&lt;p&gt;"Checkout is broken on mobile sometimes" is not a useful input. Neither is "I clicked around and it failed."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How AI helps:&lt;/strong&gt; give it the report, any stack trace, and a bit of context. Ask it to turn that mess into a reproducible path, a test matrix, and candidate assertions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical example:&lt;/strong&gt; a PM drops this into Slack:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;User says password reset fails after they open the email on iPhone and go back to the app.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is not ready for engineering. AI can turn it into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;likely repro conditions&lt;/li&gt;
&lt;li&gt;assumptions to verify&lt;/li&gt;
&lt;li&gt;exact steps to test&lt;/li&gt;
&lt;li&gt;likely layers involved&lt;/li&gt;
&lt;li&gt;candidate integration or E2E test cases
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Turn this bug report into a reproducible test plan.

Output:
- assumptions
- exact repro steps
- likely affected layers
- edge cases to test
- one candidate automated test

Bug report:
"User says password reset fails after they open the email on iPhone and go back to the app."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why it saves time:&lt;/strong&gt; you stop spending the first 30 minutes translating vague human language into engineer language.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Generate first-draft docs right after shipping a feature
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; docs are always "we'll do it after this PR lands." Then nobody does it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How AI helps:&lt;/strong&gt; after the feature ships, feed it the PR description, commit summary, config changes, and a couple of examples. Let it draft internal docs, release notes, or onboarding notes while the context is still fresh.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical example:&lt;/strong&gt; you shipped a webhook retry system. You already have the raw ingredients:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PR summary&lt;/li&gt;
&lt;li&gt;env vars added&lt;/li&gt;
&lt;li&gt;retry rules&lt;/li&gt;
&lt;li&gt;failure behavior&lt;/li&gt;
&lt;li&gt;sample payloads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Turn that into a first draft immediately.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Turn these shipping notes into internal docs.

Output:
- what changed
- why it exists
- new config or env vars
- failure behavior
- examples
- what support/devs should know

Notes:
[paste PR description, commit summary, examples]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why it saves time:&lt;/strong&gt; blank-page writing is slow. Editing a decent first draft is fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Turn giant log dumps into structured debugging notes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; logs are full of repetition, noise, and timing confusion. You end up scrolling forever and still do not have a clean theory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How AI helps:&lt;/strong&gt; ask it to cluster repeated errors, reconstruct the timeline, and separate symptoms from likely root causes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical example:&lt;/strong&gt; you paste in request logs, app errors, and one queue worker trace. Instead of "look through this," you ask for structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Analyze these logs and turn them into debugging notes.

Output:
- timeline of events
- repeated errors grouped together
- likely root causes
- signals that may be red herrings
- next 5 checks to run

Logs:
[paste logs]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why it saves time:&lt;/strong&gt; the model is doing triage, not fixing production. That is exactly where it is useful.&lt;/p&gt;

&lt;p&gt;
  Optional deeper example
  &lt;br&gt;
Instead of rereading 400 lines of logs, ask for output in this shape:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Timeline&lt;/code&gt;: request received, cache miss, DB timeout, retry, downstream 502&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Recurring patterns&lt;/code&gt;: same tenant, same endpoint, same timeout window&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Most likely causes&lt;/code&gt;: connection pool exhaustion, retry storm, slow downstream dependency&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Checks to run now&lt;/code&gt;: inspect pool metrics, compare healthy tenant timings, sample failed request IDs, verify retry backoff, look for deploy correlation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That gives you a debugging worksheet instead of a wall of text.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Extract action items from messy meetings or issue threads
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; a single GitHub issue or Slack thread can contain decisions, half-decisions, contradictions, and silent assumptions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How AI helps:&lt;/strong&gt; make it extract owners, blockers, decisions, and unanswered questions in a format your team can actually act on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical example:&lt;/strong&gt; after a product meeting, you have rough notes plus a noisy thread with frontend, backend, and design comments mixed together. Ask AI to convert it into a clean action list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Read this meeting transcript and issue thread.

Extract:
- decisions made
- open questions
- blockers
- owners if identifiable
- next actions

Format it as a concise engineering handoff.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why it saves time:&lt;/strong&gt; you stop rewriting the same conversation into tickets by hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Create migration checklists before touching code
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; upgrades fail because teams start with code changes instead of scope control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How AI helps:&lt;/strong&gt; before you touch the repo, use AI to generate a migration checklist that covers dependency risks, config changes, affected app areas, test plan, rollout risks, and rollback points.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flfdgo4f9q9nxq3drughr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flfdgo4f9q9nxq3drughr.gif" alt="Clippy-style debugging animation" width="480" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;GIF source: &lt;a href="https://giphy.com/gifs/MicrosoftCloud-msbuild-microsoft-build-IZ7R7Mok8NXzyGmlvE" rel="noopener noreferrer"&gt;Microsoft Cloud on Giphy&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical example:&lt;/strong&gt; you need to upgrade a framework, SDK, or ORM. Do not begin with "let's bump the version and see what breaks."&lt;/p&gt;

&lt;p&gt;Start here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create a migration checklist for this upgrade.

Context:
- current version: X
- target version: Y
- package list
- build/test scripts
- app patterns in use

Output:
- risky areas
- code patterns to audit
- config changes
- test plan
- rollout plan
- rollback plan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why it saves time:&lt;/strong&gt; migrations get expensive when you discover risk too late. A checklist is cheaper than a surprise.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Review PRs for edge cases and missing tests
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; most AI PR reviews are too polite and too shallow. "Looks good" is useless.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How AI helps:&lt;/strong&gt; give it a diff and ask it to act like a skeptical reviewer. Not a cheerleader. Not a linter. A reviewer looking for behavioral gaps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical example:&lt;/strong&gt; a PR claims to "fix duplicate invoice sending." AI can inspect the patch and ask the questions a rushed human reviewer might miss:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what happens on retries?&lt;/li&gt;
&lt;li&gt;what if the process crashes after write but before send?&lt;/li&gt;
&lt;li&gt;what if two workers race?&lt;/li&gt;
&lt;li&gt;where is the regression test?
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Review this PR diff like a skeptical staff engineer.

Focus on:
- edge cases
- behavior changes not mentioned in the title
- missing tests
- rollback risk
- race conditions
- failure states

Diff:
[paste diff or summary]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why it saves time:&lt;/strong&gt; it gives you a second set of eyes on the logic, not just the syntax.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Turn vague product requests into implementation plans
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; product asks are often written at the wrong altitude. Too vague to estimate. Too specific to question. Dangerous combination.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How AI helps:&lt;/strong&gt; use it to turn the request into an engineering plan with assumptions, scope boundaries, data changes, states, risks, and open questions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical example:&lt;/strong&gt; "We need users to pause subscriptions temporarily."&lt;/p&gt;

&lt;p&gt;That sounds simple until you ask the obvious follow-ups:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;billing implications?&lt;/li&gt;
&lt;li&gt;proration?&lt;/li&gt;
&lt;li&gt;expiration?&lt;/li&gt;
&lt;li&gt;admin override?&lt;/li&gt;
&lt;li&gt;analytics?&lt;/li&gt;
&lt;li&gt;email flows?&lt;/li&gt;
&lt;li&gt;API contract?&lt;/li&gt;
&lt;li&gt;mobile states?&lt;/li&gt;
&lt;li&gt;edge case when payment fails during resume?
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Turn this product request into an implementation plan.

Output:
- assumptions
- open questions
- API/data model changes
- frontend states
- edge cases
- telemetry
- smallest shippable version
- risks

Request:
"We need users to pause subscriptions temporarily."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why it saves time:&lt;/strong&gt; you walk into planning with something sharper than vibes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Toy Use vs Real Workflow
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Toy use&lt;/th&gt;
&lt;th&gt;Real workflow&lt;/th&gt;
&lt;th&gt;Why the workflow wins&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"Build me a Snake game"&lt;/td&gt;
&lt;td&gt;Turn a product request into an implementation plan&lt;/td&gt;
&lt;td&gt;It reduces ambiguity before code starts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Write a regex for me"&lt;/td&gt;
&lt;td&gt;Turn a vague bug report into a test case plan&lt;/td&gt;
&lt;td&gt;It helps you reproduce and verify real bugs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Summarize this file"&lt;/td&gt;
&lt;td&gt;Review a PR for missing tests and edge cases&lt;/td&gt;
&lt;td&gt;It finds risk, not just words&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Explain Docker like I'm five"&lt;/td&gt;
&lt;td&gt;Create a migration checklist before an upgrade&lt;/td&gt;
&lt;td&gt;It prevents expensive mistakes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"What does this stack trace mean?"&lt;/td&gt;
&lt;td&gt;Convert logs into structured debugging notes&lt;/td&gt;
&lt;td&gt;It gives you a path to investigate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Write release notes"&lt;/td&gt;
&lt;td&gt;Generate docs right after shipping from real changes&lt;/td&gt;
&lt;td&gt;It captures context before it disappears&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Brainstorm app ideas"&lt;/td&gt;
&lt;td&gt;Extract action items from meetings and issue threads&lt;/td&gt;
&lt;td&gt;It turns conversation into execution&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What Changed for Me
&lt;/h2&gt;

&lt;p&gt;I stopped asking AI for brilliance.&lt;/p&gt;

&lt;p&gt;I started asking it for leverage.&lt;/p&gt;

&lt;p&gt;That changed everything.&lt;/p&gt;

&lt;p&gt;I use it less like a genius intern and more like a formatting engine for engineering work. It is great at turning messy input into clean output:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;vague report into test plan&lt;/li&gt;
&lt;li&gt;raw logs into debugging notes&lt;/li&gt;
&lt;li&gt;shipped code into docs&lt;/li&gt;
&lt;li&gt;discussion into actions&lt;/li&gt;
&lt;li&gt;request into scope&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the pattern.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI is not most useful in the middle of coding. It is often most useful at the handoff points around coding.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is this just ChatGPT with better prompts?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not really. The important part is not the prompt text. It is the workflow shape. You are feeding AI messy inputs that already exist in your day and asking for structured outputs you actually use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should AI write production code too?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sometimes, yes. But that is not the biggest unlocked value for most teams. Code generation gets attention. Workflow acceleration saves time more reliably.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What about privacy and security?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use your brain. Do not paste secrets, private customer data, or sensitive production material into tools that are not approved for it. Redact first. Use the right environment. Treat AI like any other external system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Won't this create more cleanup work?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Only if you ask for finished answers when you really need first drafts. The trick is to use AI for scaffolding, synthesis, and structure. You do the final judgment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;A lot of developers are disappointed by AI because they are using it for low-stakes parlor tricks.&lt;/p&gt;

&lt;p&gt;The better use is boring on purpose.&lt;/p&gt;

&lt;p&gt;It helps with the stuff that slows real work down: clarifying, organizing, checking, summarizing, planning, and documenting.&lt;/p&gt;

&lt;p&gt;That is how it stops being a toy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/new" class="crayons-btn crayons-btn--primary"&gt;What workflow saves you the most time? Share it in the comments.&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;If you already have a workflow like this, I want to hear it. And if you think one of these is overrated, even better. Those are usually the best comment sections.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
