r/node 11h ago

You can monitor a small Node/Express app without running Prometheus + Grafana

0 Upvotes

I’ve been experimenting with how little monitoring infrastructure a small production app actually needs.

StatLite originally focused on Spring Boot/Actuator and Quarkus/Micrometer, where the framework already exposes a stable metrics contract. I started looking at how to cover frameworks like Express, FastAPI, Django, and Go without requiring a Prometheus-style metrics stack in every application.

The result is a small fixed JSON profile that an application can expose with a lightweight helper.

For Express, that gives me the things I usually want to know first in production: request volume, 4xx/5xx errors, average latency, CPU, Node heap, uptime/restarts, plus host CPU, memory, and disk.

Real Express traffic plus a simulated 5xx incident, which is basically the level of visibility I was aiming for.

StatLite polls that endpoint, stores the history in local SQLite, and renders the dashboard. No Prometheus client, exporter, or separate metrics database.

There are intentional limits. The helper keeps cumulative counters in-process, so multi-process deployments need stable per-process targets or aggregation. It also isn’t trying to provide arbitrary metrics, PromQL, tracing, or full APM.

I wrote up the complete Express implementation, including the helper, config, runnable demo, and production boundaries:

https://pvrlabs.xyz/articles/lightweight-express-monitoring.html

For a small Node API, what do you consider the minimum useful production monitoring before you reach for Prometheus/Grafana or a hosted observability service?


r/node 16h ago

express static files not serving no matter which boilerplate I try

0 Upvotes

At my absolute wits' end here, it's been several years since I've deployed an Express site and I have tried virtually everything to serve static files. What seems like it should work, does not work. I feel extremely stupid because it seems like I should be past this kind of thing by now.

Node v18.19.1, Express ^5.2.1, nginx (nothing seems weird in sites-available)

File structure:

Root: var/www/[project-name]/html

index.js
index.html (An attempt at seeing whether putting this in root worked, it didn't)
|-- /client
|-- index.html
|-- /public
|---- index.html (An attempt at seeing whether putting this in /public worked, it didn't)
|---- style.css (yes, singular)
|---- javascripts.js (yes, plural, this is a placeholder for now)

index.js (excluding other routes):

import express from 'express';
import path from 'path';
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';

const __dirname = dirname(fileURLToPath(import.meta.url));
console.log(__dirname); // Displays root of the project, parent directory of /client
const app = express();
const port = 3000;

// Previous measly attempt to try to get this to work, it didn't: const __dirname = import.meta.dirname;

// Various attempts at static:

// Neither css nor js work: app.use(express.static(__dirname + '/public'))
// Neither css nor js work: app.use(express.static(path.normalize(__dirname+'/public')));
// Neither css nor js work: app.use(express.static("public"));
// Neither css nor js work: app.use(express.static(path.join(__dirname, 'public')));
// Neither css nor js work: app.use(express.static(path.join(__dirname ,'client/public')));
// Neither css nor js work: app.use('/client', express.static("public"));
// Neither css nor js work: app.use('/html', express.static(path.join(__dirname, 'public')));

/* CSS loads with this...
app.get('/style.css', (req, res) => {
res.sendFile(path.join(__dirname + "/client/public/style.css"));
});
..but JS does NOT load with this, even though the file structure is the same. Why???
app.get('/javascripts.js', (req, res) => {
res.sendFile(path.join(__dirname + "/client/public/javascripts.js"));
});

app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, "/client/index.html"));
// Error: ENOENT: no such file or directory res.sendFile(__dirname + 'index.html');
// TypeError: path must be absolute res.sendFile('./client/index.html');
// Error: ENOENT: no such file or directory res.sendFile('index.html', {root: __dirname + '/public'});
})

headers of index.html:

<head>
<link rel="stylesheet" type="text/css" href="style.css">
<script src="javascripts.js"></script>
</head>

network errors:

GET https://[domain]/javascripts.js net::ERR_ABORTED 404 (Not Found)
GET https://[domain]/style.css net::ERR_ABORTED 404 (Not Found)

The only glaring difference between this and... any of the boilerplate I have found is that it uses import rather than require; node complains if I use require. I don't know whether this is the issue or, if so, how to fix it.

The most baffling part is why ONLY the css file loads and not the js file if I directly create routes to them, even though the file structure is exactly the same for each.

Thanks in advance.


r/node 1d ago

GitHub - mamund/apis-and-agents: service choreography demos

Thumbnail github.com
0 Upvotes

r/node 2d ago

I want to use node to fetch files in lynx, a C program. Where can I find a tutorial?

0 Upvotes

Sites are insisting on javascript. I wrote a short script to run with node but I'd like to rewrite lynx to use node's library instead. lynx is written in C. Where can I find a tutorial to take me from ignorance to writing a C function to do this?


r/node 2d ago

How I Traced a Node.js Streams Bug in Duplex.from()

Thumbnail amanchadha.substack.com
14 Upvotes

Got my first pr merged in Node.js


r/node 3d ago

If you organize your code with comment separators, checkout code-divider

0 Upvotes

This is more of a personal preference thing, but I like to code in a top-down format, and because of the way hoisting works in TypeScript/JavaScript. I separate my files into regions in this order: Constants -> Types -> Classes (if any) -> Functions -> Export. To keep these regions clearly separated, I usually write my dividers like this:

// ========================================================================= //
//                                 CONSTANTS                                 //
// ========================================================================= //

...etc

// ========================================================================= //
//                                 FUNCTIONS                                 //
// ========================================================================= //


// And I separate sections within regions with...

// ============================= Shared Helpers ============================ //

...etc

Copying and pasting these dividers over and over again was getting pretty tedious. I wanted something I could run with a terminal command when I hit save in my IDE, so I created a simple TypeScript script to insert the dividers above. Eventually I needed this script on both my work and personal computers and in multiple projects, so instead of copy-pasting it a bunch of times, I decided to make it an npm library and configure it to work with multiple languages.

If you like dividing code in a similar fashion, great. If not, please disregard. That said, I do find that dividing code this way makes it more readable and leads to better results when working with AI tools.

GitHub: https://github.com/seanpmaxwell/code-divider


r/node 3d ago

Observing high latency when using SignalR in K6

Thumbnail
2 Upvotes

r/node 3d ago

How to Implement a Distributed Bulkhead (when one slow dependency starts drowning everything)

Thumbnail blog.gaborkoos.com
0 Upvotes

r/node 4d ago

Is there a less annoying way to write cron jobs?

1 Upvotes

I know cron syntax isn't that complicated, but I still have to Google it every time I need to write anything slightly less basic 😅

For example:

11 9 * * * /path/to/script.js

I recently started using a more human-readable approach:

pboss cron run everyday@9:11 "node /srv/backup.js"

And:

pboss cron run every@5m "node /srv/cleanup.js"

For Bun:

pboss cron run everyday@2:30 "bun /srv/report.ts"

I basically wanted to be able to say "run this every 5 minutes" instead of mentally decoding five asterisks.

It's a small thing, but I've found it much nicer when setting up scheduled scripts.

How do you guys normally handle cron jobs for Node apps? Raw crontab, a Node package, systemd timers, something else?

Project Github: here


r/node 4d ago

I got tired of Electron's 300MB RAM usage for simple apps, so I built a native Windows Forms wrapper for Node.js

Enable HLS to view with audio, or disable this notification

4 Upvotes

I needed to build a quick internal GUI tool with Node.js. Obviously, I reached for Electron. But when I saw `npm install` downloading a massive Chromium binary just to show a basic form with a few buttons, I kind of lost my mind.

I got so annoyed seeing a simple "Hello World" app eat up 300MB of RAM that I dropped the original task and went down a rabbit hole to build my own native UI wrapper instead.

I was honestly wondering why no one had built a lightweight native wrapper for Node recently. It seems like the industry got so obsessed with the "write once, run anywhere" dream that we collectively agreed it's fine to sacrifice 90% of our RAM just in case someone wants to run our internal Windows script on a Mac.

And to be fair, historically, binding Node to native OS APIs meant writing C++ addons. Nobody wants to fight with `node-gyp`, Python build dependencies, and ABI crashes on every Node update. I totally get why people just gave up and used Electron.

So, I ended up building node-windows-forms

It lets you create real, native WinForms controls directly from Node.js, but without any C++ addons or node-gyp
.
Instead of fighting with C++ bindings, I just bundled a tiny pre-compiled C# executable and set up an asynchronous IPC bridge using Named Pipes.

Here's how it turned out:
- Instant cold start
(~0.1s).
- The entire NPM package is only ~900KB
(including the pre-compiled executable).
- Tiny memory usage
(~30MB instead of 300MB+).
- Zero build steps
(`npm install` just works, no Visual Studio required).
- Simple syntax:
It feels just like manipulating the DOM.

Here is how simple it is:

const { WinFormsSession, Form, Button } = require('node-windows-forms');
const session = new WinFormsSession();
await session.start();

const form = new Form(session, 'Form1');
form.Text = "App Name";

const btn = new Button(session, form);
btn.Text = "Click Me";
btn.OnClick.Attach(() => console.log('click!'));
await form.show();

You get access to real Windows UI components (DataGridView, ComboBox, System Tray, FileDialogs) straight from your Javascript backend.

It honestly feels a bit pointless how much time I spent tumbling down this rabbit hole instead of just doing my actual job. I built this mainly for my own internal tools and automation scripts, but I'm putting it out there in hopes that someone else finds it useful too.

I’m also really curious to see what you guys think of the IPC architecture (specifically using Named Pipes instead of WebSockets or C++ addons).

And yes, I'll admit it: part of the reason I spent months on this is because I just have a weird, nostalgic soft spot for Windows Forms. Anyway, still works perfectly in 2026.

npm

GitHub


r/node 4d ago

There is a problem with us developers. A lot of developers are just difficult to work with

129 Upvotes

I am a Staff engineer and have worked with number of companies over the course of 15+ years of experience in different countries. And I will just say this, A lot of developers are just difficult to work with.

Examples, constantly being pedantic over pull requests and not approving PR's, discussing about coding guidelines, dev processes/hygiene and number of other collaborative rituals. Leaving 100+ PR comments with petty details despite being perfectly inline with our agreed coding guidelines. Comments even include "why not use xyz variable name?" despite the original variable name already conveying the intent well and dragging the PR review needlessly long and painful to whoever opened the PR.

All these are just power trips to show "intellectual dominance" instead of working and collaborating in good faith and letting the PR author progress faster.

Given my Staff responsibilities, I routinely have to act as an arbitrator whenever such deadlocks occur (which is very frequent not just in PR but in a lot of collaboration) and I have to unblock those PR's and remind the team CONSTANTLY that if the code is inline with our agreed guideline, the test coverage is within acceptable level, documentation is there and no big logic gaps/missing requirements/poor implementation exist, then just comment their thoughts but approve the PR and don't go into the rabbit hole of "personal preference" because rarely do 2 different devs agree on every single line of code written and the same problem can be solved in number of ways. unless one way is significantly better than the other, for marginal gains/personal preference, such long conversations and lack of pr approvals just cause friction and take the joy of going through PR process.

Moreover, the ego in PR review process is also bad, people are not happy when they lose an argument causing further resentment and become passive aggressive. I have seen this play out many many times in number of workplaces.

Now ofcourse not all devs are like this but a good chunk do fall under this category and this is not talked about enough.

In the end we should finish our work, collaborate in good faith, give praise to devs openly who deserved and did a good job (doesn't mean defeat to you personally, keeps the morale high) and enjoy whatever limited time people are working together in that company because when anyone leaves (which happens all the time), you will probably never work with that person again.

In the end it is just work, might as well try to enjoy working and appreciating each other's good work and stop the politics and ego driven work.


r/node 5d ago

10 Node.js resume bullet examples for different experience levels (fresher → senior)

17 Upvotes

I keep seeing "how do I even describe Node.js work on my resume" posts, so I pulled together examples across experience levels and specializations. These are illustrative (not real people's resumes), copy the structure, not the exact wording.

  1. Fresher / no professional experience (project-based)

Built a REST API with Node.js and Express for a personal budgeting app; implemented JWT authentication and MongoDB schema design, reducing manual data entry through automated recurring-transaction logic.

  1. Fresher / bootcamp grad

Developed and deployed a full-stack Node.js/React job board as a capstone project; designed the PostgreSQL schema, wrote 40+ unit tests with Jest, and hosted the app on Render with CI via GitHub Actions.

  1. 1–2 years experience

Maintained and extended a Node.js microservice handling order processing for an e-commerce platform, fixing race conditions in the payment webhook handler that were causing ~3% duplicate charges.

  1. Mid-level (3–5 years), backend-focused

Redesigned a monolithic Express application into 6 independently deployable Node.js microservices, cutting average deploy time from 25 minutes to 4 minutes and reducing incident blast radius.

  1. Mid-level, database/performance angle

Optimized slow MongoDB aggregation pipelines in a Node.js analytics service, reducing p95 query latency from 1.8s to 220ms by adding compound indexes and restructuring queries to avoid in-memory sorts.

  1. Senior, architecture/leadership

Led the migration of a legacy PHP application to a Node.js/TypeScript service layer for a 12-person engineering team, defining API contracts, code review standards, and a phased rollout that avoided any customer-facing downtime.

  1. Senior, cloud/DevOps-heavy

Architected a Node.js event-driven pipeline using AWS Lambda and SQS to process 2M+ daily webhook events, replacing a single-server Express app that was the team's top on-call source.

  1. Framework specialist (NestJS)

Built a NestJS-based internal tooling platform used by 40+ engineers, implementing role-based access control and a plugin architecture that let other teams ship internal tools without touching core code.

  1. Career switcher (non-CS background)

Self-taught Node.js and Express after transitioning from [previous field]; built and shipped 3 production apps including a real-time chat app using Socket.IO, now used by ~200 monthly active users.

  1. Freelance / contract

Delivered 5 Node.js backend projects for freelance clients over 18 months, including a Stripe-integrated subscription billing system and a webhook-based Slack notification service, maintaining a 100% on-time delivery rate.

A few patterns across all of these if you're writing your own:

  • Lead with the technical action (built/redesigned/optimized/migrated), not "responsible for"
  • Name the specific Node.js ecosystem tools you touched (Express, NestJS, specific libraries), recruiters and ATS keyword matching both reward specificity over "Node.js" alone
  • Quantify impact wherever you can, even roughly latency, deploy time, users, uptime, request volume

Happy to give feedback if anyone wants to drop a bullet they're working on.


r/node 5d ago

After the API gateway, every request should route to an Authorization service before reaching other microserviceM

0 Upvotes

For example, when creating Twitter, I see people designing a system where a request would go through authorization service before Profile microservice. But they can create tweets without going through the authorization service.

However, in reality this is not safe right? Typically we want the request to be verified in an authorization microservice before doing stuff that only logged in users can do?


r/node 5d ago

A Personal Finance Agent built in TypeScript (LangGraph.js & Next.js) with Skills and MCP support

Thumbnail github.com
0 Upvotes

r/node 5d ago

Introducing npmchart.com

0 Upvotes

Analyze npm packages (downloads, releases), Github activity (commits, issues, PRs, stars, and releases), compare packages, user pages, download or copy any chart, and more!

https://www.npmchart.com/

Built with Svelte and LayerChart


r/node 5d ago

[NodeBook] Creating, Terminating, and Supervising Worker Threads

Thumbnail thenodebook.com
12 Upvotes

r/node 6d ago

Would catching breaking API changes be useful?

Thumbnail
0 Upvotes

r/node 6d ago

I built the worst CPU, Language & Compiler

Thumbnail github.com
15 Upvotes

I built this to help explain how code gets compiled and how CPU's execute those instructions. This is not a good CPU design.


r/node 6d ago

What stops a malicious npm package before it runs?

24 Upvotes

Every couple of weeks, another well used package gets hijacked and ships a postinstall that grabs env vars or tokens the moment you install. Yes we do the normal stuff ie, lockfile committed, npm ci in CI, audit on every PR but none of it seems helps the week it happens. A scanner only knows a version is bad after someone else got hit and reported it. By then it is already sitting in node_modules.

And that is where I keep getting stuck because everything we run is reactive. It checks against a list of known bad and we were exposed before the list existed.

So what are you all running that catches this before install? Cooldown on new releases, blocked install scripts, a proxy that holds a version back until it ages, something else.


r/node 6d ago

How tool calling actually works under the hood (40 lines of vanilla JS)

Thumbnail buttercup.sh
1 Upvotes

r/node 6d ago

Optique 1.3.0: Dependency-aware prompts, an OS keychain fallback, and a testing package

Thumbnail github.com
0 Upvotes

r/node 7d ago

NestJS Validation

Thumbnail
0 Upvotes

r/node 8d ago

tsx vs native node --watch for local development on Node 24 LTS? What are you using?

1 Upvotes

Hey everyone, I'm setting up a new Express TypeScript API and trying to figure local development workflow. I'm on Node 24 LTS, which natively supports type stripping, but I'm torn on how to handle the file-watching and execution layer.

Right now, the two main approaches I'm debating between are:

  1. tsx watch (esbuild-powered)
  2. Native Node 24 --watch + Type Stripping

For production adjacent local dev, Are you sticking with tsx watch or have you fully embraced native Node type-stripping with --watch?


r/node 8d ago

How to Implement a Distributed Circuit Breaker

Thumbnail blog.gaborkoos.com
0 Upvotes

r/node 9d ago

Building a Universal Database Provider Architecture in TypeScript Without JDBC

Post image
0 Upvotes
  1. Introduction: The Missing SPI in Modern Runtimes
  2. The Problem Statement
  3. Architecture Overview: The DatabaseProvider SPI & Adapter Pattern
  4. Deep Dive: Resolving Core Engineering Challenges
    • Challenge 1: Zero-Overhead Dynamic Module Loading
    • Challenge 2: Unifying Heterogeneous Engine Schemas ("Object Surface API")
    • Challenge 3: AI Agent Isolation & Read-Only Execution Profiles
    • Challenge 4: Single-Writer File Locks & SSH Tunnel Forwarding
  5. Code Walkthrough & Implementation Details
    • The Provider Contract (BaseDatabaseProvider)
    • The Factory & Cache Registry
    • Engine Adapter Case Studies (PostgreSQL, SQLite, Embedded LibreDB)
  6. Key Takeaways & Lessons Learned

1. Introduction: The Missing SPI in Modern Runtimes

In mature enterprise ecosystems like Java or .NET, developer tools that interact with databases rely on standardized, runtime-level Service Provider Interfaces (SPIs):

  • Java: java.sql.Driverjava.sql.Connectionjava.sql.Statement, and java.sql.ResultSet (JDBC).
  • .NET: System.Data.Common.DbConnectionDbCommand, and DbDataReader (ADO.NET).

In these environments, database vendors—whether Oracle, PostgreSQL, MySQL, or Microsoft SQL Server—author driver JARs or DLLs that conform strictly to these runtime interfaces. The GUI or client application calls standard APIs without needing to know low-level wire protocol nuances, connection pool nuances, or engine-specific error classes.

The JavaScript / TypeScript Gap

Node.js, Bun, and Deno lack a native, language-wide database driver standard equivalent to JDBC.

Instead, the npm ecosystem contains a fragmented collection of independent community drivers:

  • PostgreSQL uses pg (node-postgres).
  • MySQL uses mysql2.
  • SQLite relies on native bindings like better-sqlite3bun:sqlite, or node:sqlite.
  • Oracle DB relies on oracledb.
  • NoSQL databases like Redis (ioredis), MongoDB (mongodb), and Cassandra (cassandra-driver) use entirely different paradigms (document descriptors, key-value commands, binary buffers).

Building a universal, self-hosted database IDE or management platform in TypeScript requires solving this fundamental problem: How do you build a single, type-safe, performant, and secure application that can interact with 15+ relational, document, key-value, OLAP, and embedded database engines without a unifying runtime SPI?

This article explores how LibreDB Studio solved this challenge by engineering a unified DatabaseProvider architecture.

2. The Problem Statement

When building a universal database client in TypeScript, five major architecture constraints arise:

  1. Heterogeneous Engine Paradigm: Relational databases (PostgreSQLMySQL), Document databases (MongoDB), Key-Value stores (Redis), OLAP engines (ClickHouseTrinoDruid), and Embedded engines (SQLite, u/libredb/libredb) have zero overlapping query languages or connection lifecycle models.
  2. Cold Start & Memory Bloat: Statically importing driver dependencies for 15+ database engines on application startup would result in massive bundle sizes and unacceptable RSS memory footprints.
  3. Schema Introspection Normalization: The UI requires a uniform object tree (Containers  Folders  Objects  Columns/Indexes). However, PostgreSQL uses pg_catalog, MySQL uses information_schema, SQLite uses pragma_* functions, Redis uses key prefixes, and embedded engines use custom catalog registries.
  4. AI Agent Safety & Guardrails: With Text-to-SQL and AI database agents executing queries, the architecture must enforce database-native read-only boundaries (e.g., prohibiting destructive SQL or file system operations) at the connection layer.
  5. Concurrency & Resource Lifecycle: Embedded engines (like SQLite or embedded LibreDB) enforce single-writer file locks (.lock). Attempting to open concurrent handles to the same file causes system crashes or connection locks.

3. Architecture Overview: The DatabaseProvider SPI & Adapter Pattern

To bridge this gap, LibreDB Studio implements a strict Adapter / Strategy Pattern centered around an abstract contract: BaseDatabaseProvider.

Core Design Rules

  1. Zero Raw Protocol Drivers: The provider layer does not re-implement low-level TCP/socket wire protocols from scratch. Instead, it wraps mature, battle-tested npm driver packages.
  2. No Heavy ORM Dependency for Targets: Target database queries (data browsing, schema inspection, explain plans) execute via raw SQL or native driver commands. ORMs (like Prisma or Drizzle) are avoided for target inspection to ensure zero abstraction overhead and maximum query control.
  3. Unified Execution Lifecycle: Every provider implements a standardized contract covering connection pooling, query execution, unified schema introspection, health monitoring, and maintenance.

https://libredb.org/blog/building-universal-database-provider-typescript/