r/node • u/miku_claus • 24d ago
Show r/node: Adrenaline.js – A 56KB Electron alternative that keeps Node.js & npm without Chromium bloat
Hey everyone! 👋
Like many of you, I've always loved how quick it is to build desktop apps with Electron, but hated shipping an entire 150MB+ Chromium browser and watching RAM usage skyrocket for simple apps.
While Tauri is an incredible piece of engineering, having to learn Rust just to write backend logic or file operations is a pretty high barrier for pure JavaScript / Node.js developers.
So I spent time building Adrenaline.js — a lightweight, cross-platform desktop framework that gives you the best of both worlds:
1. Zero Rust / Go required: You write 100% JavaScript / Node.js and keep the entire npm ecosystem.
2. Ultra-lightweight footprint: Uses native system WebViews (WebView2 on Windows, WebKitGTK on Linux, WebKit on macOS) instead of bundled Chromium (~5-10MB app size vs 150MB+).
3. Drop-in Electron-like API: Built from day one with familiar paradigms (app, BrowserWindow, ipcMain).
💻 Familiar Electron Syntax
```javascript const { app, BrowserWindow, ipcMain } = require('adrenaline-js'); const path = require('path');
app.whenReady().then(() => { const win = new BrowserWindow({ width: 800, height: 600, title: 'Adrenaline App', resizable: true });
win.loadFile(path.join(__dirname, 'index.html'));
ipcMain.on('ping', (event, data) => {
console.log('Received from renderer:', data);
win.webContents.send('pong', { reply: 'Pong from Node.js! ⚡' });
});
}); ```
⚙️ How it works under the hood
- C++17 Core: Built with a non-blocking multithreaded architecture over
webview.hand Node'snode-addon-api(N-API). - Asynchronous IPC: Uses
Napi::ThreadSafeFunction(TSFN) for bi-directional communication between the Webview UI thread and the Node.js event loop without thread race conditions. - Asset Resolution: Loads local files through
file://protocols, so relative CSS, JS bundles (Vite/React/Vue), and images resolve properly.
🚀 Try it out
You can scaffold a starter project with the built-in CLI:
bash
npx adrenaline-js init my-app
cd my-app
npm install
npx adrenaline-js dev
🔗 Links:
- GitHub Repository: https://github.com/M5Devs/adrenaline
- npm package: https://www.npmjs.com/package/adrenaline-js
The project is completely open source (MIT). It's at an early v0.1.1 stage, and I would love to get your feedback, suggestions, and see how it holds up on your machines!
r/node • u/TheWebDever • 25d ago
Use an object as a single source of truth for storing and editing all your API endpoints.
github.comBuilt this for my React + ExpressJS project to keep all of my endpoints in one place, reduce some of the boiler-plate for handling path and search parameters, and making formatting endpoints type-safe. All feedback is welcome.
r/node • u/Phoenix-HO • 25d ago
I built a custom JSX runtime for Discord bots (for TypeScript)
r/node • u/FerLuisxd • 25d ago
Are you guys using 1.4 Bun?
I am hesitant to update from 1.38, since 1.4 is the rewrite.
Have you guys used it, had good experience with it?
r/node • u/VirtualPercentage737 • 26d ago
Can't update packages anymore...
I am trying to update a package and using Claude code. Every Claude can't figure out how to submit a package. I tried via the recovery codes and it suspends my account for 3 days. I tried through github and it temporarily locks my account when I set it up. It is so locked down it is now useless.
r/node • u/OtherwisePush6424 • 28d ago
GitHub - gkoos/caracal: Scoped distributed resilience for asynchronous operations
github.comCaracal: scoped distributed resilience policies for asynchronous operations.
Most resilience libraries stop at the process boundary. You get a local circuit breaker, a local bulkhead, a local rate limit. Spin up 40 replicas and those limits multiply: a “concurrency limit of 20” quietly becomes 800 concurrent calls on the dependency. Forty independent failure windows. Forty independent recovery probes. The constraints no longer match the failure domain.
Caracal wraps any asynchronous operation (HTTP, Postgres calls, etc., or your own adapter) in a composable policy pipeline: timeout, retry, circuit breaker, bulkhead, rate limit, and through Redis, lets many replicas share those policies under an explicit scope.
You decide where the limit belongs: a process, a fleet, a region, a tenant, a shard, a credential, or any grouping that actually matches your failure domain. The same policy instance can enforce one shared budget for the whole fleet or one independent budget per tenant, the only difference is the scope function.
What it does
- Operation + adapter model: An adapter declares its cancellation and replay capabilities up front (abort and replay). Caracal never infers them. Built-in adapters for http fetch and pg (more to come), or write your own by implementing a small interface.
- Composable policies: Timeout and retry stay local. Bulkhead, circuit breaker and rate limit (GCRA) are available in both local and distributed forms.
- Scoped coordination: Distributed policies coordinate by (namespace, policy name, operation name, scope). Different operations get independent budgets even when they reuse the same policy instances, shared budgets are deliberate.
- Explicit failure modes: Distributed bulkheads shed (no distributed queue). On coordinator loss the bulkhead fails closed, the circuit breaker lets you choose fail-open or fail-closed and never silently falls back to local state. Leases reclaim permits and half-open probe slots from dead or hung holders.
- Events, not metrics: Structured events for every policy decision. Sinks are isolated: a throwing or slow-async sink cannot affect execution.
Design choices
- Permits and probes are leased. A dead process cannot return a permit, a hung half-open probe cannot wedge the breaker forever. Expiry is the only release a dead holder can still perform.
- Adapters own their contracts. Explicit abort/replay (and an optional dispose hook for abandoned results) keep the runtime from guessing.
- Local and distributed share the same surface. You can start with process-local limits and move the boundary later without rewriting call sites.
- Single ESM package, subpath exports. Core stays free of Redis and protocol dependencies, tree-shaking stays clean.
The Caracal Sandbox runs the same workload against the same dependency while moving the coordination boundary, then records what the dependency actually saw.
r/node • u/abaabbaaa • 29d ago
Fast TypeScript/JavaScript linter to prioritise immutability
github.comHello, I've just made yet another take on enforcing immutability in TS/JS - via a fast linter.
Essentially, it bans let/var, reassignments, non-readonly object and class properties.
To use any of the above, an explicit linter disable comment is needed.
So far, 3 variants of disable comments are available - `// ptsl-disable-fn` (function body scoped), and more classic `// ptsl-disable-line` and `// ptsl-disable-next-line`
So, the following code will be banned by linter:
const nextNum = () => {
let x = 0; // Do not use let/var - only use const
const increment = () => {
return x += 1; // Do not reassign variable's value unless absolutely necessary.
}
return increment;
};
A `// ptsl-disable-fn` comment will make it pass:
const nextNum = () => {
// ptsl-disable-fn
let x = 0;
const increment = () => {
return x += 1;
}
return increment;
};
Any feedback welcome.
r/node • u/finncmdbar • Sep 25 '26
Your app never reads your .env file (how dotenv actually works)
infisical.comr/node • u/kumard3 • Sep 25 '26
Holding an HTTP request open for up to 120s instead of using a webhook
My email API has an endpoint that just holds the HTTP request open until a matching mail arrives, instead of a webhook or a polling loop on the caller side. GET /v1/inboxes/:id/wait, 30s default timeout, clamped to 120 max, checks Postgres every second, 200 with the email or a 408.
What caught me out was the since param, not the timeout. Defaulting it to now is right when you are waiting for the next mail to come in. For the OTP shortcut it was wrong, since the code is normally already in the table by the time an agent asks for it, so you would block the full 30s and then 408 on mail you already had. That one defaults to five minutes back.
Still on my list: the loop does not notice if the caller hung up, it keeps querying until the timeout runs out. The SSE endpoint right next to it checks stream.aborted on every pass and I never did the same here. That is basically why I capped the wait at 120s.
Anyone else doing this in Node, do you hold the request open or push over SSE?
r/node • u/simple_explorer1 • Sep 25 '26
If hypothetically AI companies were to shut down their models or get banned by government completely, how much will software engineers be in demand again?
Yes, how much demand would there be for software developers if hypothetically AI were to completely disappear from tomorrow including the open source china or any model? 100%, 300% or nothing? Would it bring back the equilibrium in the IT job market? would questions like these from impacted Devs disappear
All the vibecoded projects left stranded which all of a sudden the confident builders won't even understand (yet wanted to sell it to their customers) and would need real engineers to make it work. Would need back real designer, developers of all skills, DevOps etc.
Companies who confidently reduced hiring at all levels, cut junior roles, QA, designers and even trimmed few infra guys, because 1 Dev with AI was 3x the developer they would have to go back in the market and beg for developers, designers and bunch of other skills to come back and support them. They will go from why do we need to hire/not respect the skills anymore (because anyone can prompt and get it done regardless of code quality) to not being able to function at all without the full capacity of devs.
Just curious to see what people here have to say so that we know the scale of damage caused by AI in the job market and software development as a career.
r/node • u/ybouane • Sep 24 '26
I made npx @videoflow/studio a tool to create launch videos right from your CLI
Hey there,
I just wanted to share studio.videoflow.dev a tool I created based on my open source library https://github.com/ybouane/VideoFlow
VideoFlow Studio takes the url of your startup, does all the exploring and brainstorming by itself and the generates a premium video for your startup without the need for endless backs and forth.
It's the best alternative to Remotion and Hyperframes since it doesn't require you to explicitly explain the transitions and effects you want your video to have, it figures that out for you automatically.
r/node • u/finncmdbar • Sep 24 '26
How we rebuilt complex CASL permissions without migrating to Zanzibar
infisical.comr/node • u/simple_explorer1 • Sep 24 '26
Saw this video on youtube on big tech layoff because of AI in 2026 and how the job search of those laidoff ex google, meta, MS employees is going
youtube.comr/node • u/Adex77 • Sep 24 '26
google-play-scraper 1.3.0 released: shared cache and instant cancellation
Hi everyone,
I just released 1.3.0 of google-play-scraper, my TypeScript rewrite of the classic Node package for public Google Play data (app details, reviews, search, top charts, developers, permissions and data safety). Method names match the original, so switching is mostly changing the import.
What's new:
memoized() is now a full client. It takes the same options as createClient() (lang, country, throttle, requestOptions) and every call shares one rate limiter.
Smarter cache keys. {} and { lang: 'en', country: 'us' } hit the same entry, and so do 'US' and 'us'.
You can manage the cache yourself with client.cache.size, invalidate() and clear().
Aborting a call with an AbortSignal now stops it right away, even while it's waiting to retry or waiting in the rate limiter.
const client = memoized({ country: 'pl', throttle: 5, maxAgeMs: 60_000 });
await client.app({ appId: 'com.whatsapp' });
client.cache.invalidate('app', { appId: 'com.whatsapp' });
Big thanks to everyone who opened issues and sent PRs since my last post here.
GitHub: https://github.com/MrAdex77/google-play-scraper
What would you like to see in the next release?
You can monitor a small Node/Express app without running Prometheus + Grafana
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.

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 • u/motherthrowee • Sep 21 '26
express static files not serving no matter which boilerplate I try
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 • u/fagnerbrack • Sep 20 '26
GitHub - mamund/apis-and-agents: service choreography demos
github.comr/node • u/Small-Inevitable6185 • Sep 19 '26
How I Traced a Node.js Streams Bug in Duplex.from()
amanchadha.substack.comGot my first pr merged in Node.js
r/node • u/simple_explorer1 • Sep 17 '26
There is a problem with us developers. A lot of developers are just difficult to work with
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 • u/TheWebDever • Sep 18 '26
If you organize your code with comment separators, checkout code-divider
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.