13 ms·
Modern Node.js Patterns
- keysdev 1y agoAbout time! The whole dragging the feet on ESM adoption is insane. The npm are still stuck on commonjs is quite a lot. In some way glad jsr came along.
- DimmieMan 1y agoI blame tooling folks doing too good of a job abstracting the problem away, and no this of course isn't a jab at them. probably 70 to 80% of JS users have barely any idea of the difference because their tooling just makes it work.
- chickenzzzzu 1y agoYet more architecture astronaut behavior by people who really should just be focusing on ifs, fors, arrays, and functions.
- triyambakam 1y agoArchitecture astronaut is a term I hadn't heard but can appreciate. However I fail to see that here. It's a fair overview of newish Node features... Haven't touched Node in a few years so kinda useful.
- chickenzzzzu 1y agoIt's a good one with some history and growing public knowledge now. I'd encourage a deep dive, it goes all the way back to at least CPP and small talk. While I can see some arguments for "we need good tools like Node so that we can more easily write actual applications that solve actual business problems", this seems to me to be the opposite. All I should ever have to do to import a bunch of functions from a file is "import * from './path'" anything more than that is a solution in search of a problem
- MrJohz 1y agoIsn't that exactly the syntax being recommended? Could you explain what exactly in the article is a solution in search of a problem?
- WickyNilliams 1y agoDid you read the article? Your comments feel entirely disconnected from its contents - mostly low level piece or things that can replace libraries you probably used anyway
- VPenkov 1y agoThe term originates from a Joel Spolsky article (or at least it's where I know it from). It's a great read: https://www.joelonsoftware.com/2001/04/21/dont-let-architecture-astronauts-scare-you/ https://www.joelonsoftware.com/2001/04/21/dont-let-architect... Feels unrelated to the article though.
- programmarchy 1y agoOne of the core things Node.js got right was streams. (Anyone remember substack’s presentation “Thinking in streams”?) It’s good to see them continue to push that forward.
- chickenzzzzu 1y agoWhy? Why is a stream better than an array? Why is the concept of a realtime loop and for looping through a buffer not sufficient?
- bblaylock 1y agoI think there are several reasons. First, the abstraction of a stream of data is useful when a program does more than process a single realtime loop. For example, adding a timeout to a stream of data, switching from one stream processor to another, splitting a stream into two streams or joining two streams into one, and generally all of the patterns that one finds in the Observable pattern, in unix pipes, and more generally event based systems, are modelled better in push and pull based streams than they are in a real time tight loop. Second, for the same reason that looping through an array using map or forEach methods is often favored over a for loop and for loops are often favored over while loops and while loops are favored over goto statements. Which is that it reduces the amount of human managed control flow bookkeeping, which is precisely where humans tend to introduce logic errors. And lastly, because it almost always takes less human effort to write and maintain stream processing code than it does to write and maintain a real time loop against a buffer. Hopefully this helps! :D
- dwb 1y agoA stream is not necessarily always better than an array, of course it depends on the situation. They are different things. But if you find yourself with a flow of data that you don't want to buffer entirely in memory before you process it and send it elsewhere, a stream-like abstraction can be very helpful.
- cluckindan 1y agoStreams have backpressure, making it possible for downstream to tell upstream to throttle their streaming. This avoids many issues related to queuing theory. That also happens automatically, it is abstracted away from the users of streams.
- flufluflufluffy 1y agowhat? This is an overview of modern features provided in a programming language runtime. Are you saying the author shouldn’t be wasting their time writing about them and should be writing for loops instead? Or are you saying the core devs of a language runtime shouldn’t be focused on architecture and should instead be writing for loops?
- deleted 1y ago[deleted]
- lvl155 1y agoThank you for this. Very helpful as I was just starting to dig into node for first time in a few years.
- tyleo 1y agoThis is great. I learned several things reading this that I can immediately apply to my small personal projects. 1. Node has built in test support now: looks like I can drop jest! 2. Node has built in watch support now: looks like I can drop nodemon!
- pavel_lishin 1y agoI still like jest, if only because I can use `jest-extended`.
- vinnymac 1y agoIf you haven't tried vitest I highly recommend giving it a go. It is compatible with `jest-extended` and most of the jest matcher libraries out there.
- pavel_lishin 1y agoI've heard it recommended; other than speed, what does it have to offer? I'm not too worried about shaving off half-a-second off of my personal projects' 5-second test run :P
- tkcranny 1y agoIt has native TS and JSX support, excellent spy, module, and DOM mocking, benchmarking, works with vite configs, and parallelises tests to be really fast.
- MrJohz 1y agoIt also can transparently run tests directly in a browser rather than mocking the DOM, which is a very cool feature that I haven't used enough yet.
- ezfe 1y agoJest is just not modern, it can't handle modern async/ESM/etc. out of the box. Everything just works in Vitest.
- deleted 1y ago[deleted]
- andrewmcwatters 1y ago[flagged]
- seattle_spring 1y ago"Anyone who disagrees with me is a junior engineer." Just because a new feature can't always easily be slipped into old codebases doesn't make it a bad feature.
- andrewmcwatters 1y agoIt’s pretty obviously bad. There was no need to design such a bad module system and basically destroy the work of others for no benefit. Yes, it’s 100% junior, amateur mentality. I guess you like pointless toil and not getting things done.
- wiseowise 1y agoESM is literally a standard. You can rant all you want, but you'll adopt it anyway.
- andrewmcwatters 1y agoNot really, from everything I can see, authors are basically forced to ship both, so it’s just another schism. Libraries that stopped shipping CJS we just never adopted, because we’re not dropping mature tech for pointless junior attitudes like this. No idea why you think otherwise, I’m over here actually shipping.
- deleted 1y ago[deleted]
- mattnewton 1y agoisn’t this just like one of the few problems that is completely solvable today with LLM coding agents?
- gabrielpoca118 1y agoDon’t forget the native typescript transpiler which reduces the complexity a lot for those using TS
- mmcnl 1y agoExactly. You don't even need --experimental-strip-types anymore.
- sroussey 1y agoIt strips TS, it does not transpile. Things like TS enums will not work.
- throwitaway1123 1y agoIn Node 22.7 and above you can enable features like enums and parameter properties with the --experimental-transform-types CLI option (not to be confused with the old --experimental-strip-types option).
- sroussey 1y agoExcellent update! Thanks!
- 9dev 1y agoDon’t use enums. They are problematic for a few reasons, but the ability to run TS code without enums without a build step should be more than enough of a reason to just use a const object instead.
- sroussey 1y agoOh, I agree.
- theThree 1y agoIt's still not ready for use. I don't care Enum. But you can not import local files without extensions. You can not define class properties in constructor.
- farkin88 1y agoThe killer upgrade here isn’t ESM. It’s Node baking fetch + AbortController into core. Dropping axios/node-fetch trimmed my Lambda bundle and shaved about 100 ms off cold-start latency. If you’re still npm i axios out of habit, 2025 Node is your cue to drop the training wheels.
- yawnxyz 1y agonode fetch is WAY better than axios (easier to use/understand, simpler); didn't really know people were still using axios
- Raed667 1y agoI do miss the axios extensions tho, it was very easy to add rate-limits, throttling, retry strategies, cache, logging .. You can obviously do that with fetch but it is more fragmented and more boilerplate
- farkin88 1y agoTotally get that! I think it depends on your context. For Lambda where every KB and millisecond counts, native fetch wins, but for a full app where you need robust HTTP handling, the axios plugin ecosystem was honestly pretty nice. The fragmentation with fetch libraries is real. You end up evaluating 5 different retry packages instead of just grabbing axios-retry.
- hiccuphippo 1y agoSounds like there's space for an axios-like library built on top of fetch.
- lllllllllllll6 1y ago[dead]
- farkin88 1y agoI think that's the sweet spot. Native fetch performance with axios-style conveniences. Some libraries are moving in that direction, but nothing's really nailed it yet. The challenge is probably keeping it lightweight while still solving the evaluating 5 retry packages problem.
- kfuse 1y agoNode now has limited supports for Typescript and has SQLite built in, so it becomes really good for small/personal web oriented projects.
- yawnxyz 1y agoI feel like node and deno conventions are somehow merging (which is a good thing)
- mdhb 1y agoI think this partly at least is coming from the WinterCG efforts.
- upcoming-sesame 1y agoYes around web standards
- azangru 1y agoMatteo Collina says that the node fetch under the hood is the fetch from the undici node client [0]; and that also, because it needs to generate WHATWG web streams, it is inherently slower than the alternative — undici request [1]. [0] - https://www.youtube.com/watch?v=cIyiDDts0lo https://www.youtube.com/watch?v=cIyiDDts0lo [1] - https://blog.platformatic.dev/http-fundamentals-understanding-undici-and-its-working-mechanism https://blog.platformatic.dev/http-fundamentals-understandin...
- sieabahlpark 1y ago[dead]
- vinnymac 1y agoIf anyone is curious how they are measuring these are the benchmarks: https://github.com/nodejs/undici/blob/main/benchmarks/benchmark.js https://github.com/nodejs/undici/blob/main/benchmarks/benchm... I did some testing on an M3 Max Macbook Pro a couple of weeks ago. I compared the local server benchmark they have against a benchmark over the network. Undici appeared to perform best for local purposes, but Axios had better performance over the network. I am not sure why that was exactly, but I have been using Undici with great success for the last year and a half regardless. It is certainly production ready, but often requires some thought about your use case if you're trying to squeeze out every drop of performance, as is usual.
- rco8786 1y agoI've been away from the node ecosystem for quite some time. A lot of really neat stuff in here. Hard to imagine that this wasn't due to competition in the space. With Deno and Bun trying to eat up some of the Node market in the past several years, seems like the Node dev got kicked into high gear.
- amclennon 1y agoSome good stuff in here. I had no idea about AsyncIterators before this article, but I've done similar things with generators in the past. A couple of things seem borrowed from Bun (unless I didn't know about them before?). This seems to be the silver lining from the constant churn in the Javascript ecosystem
- prmph 1y agoI think slowly Node is shaping up to offer strong competition to Bun.js, Deno, etc. such that there is little reason to switch. The mutual competition is good for the continued development of JS runtimes
- gear54rus 1y agoSlowly, yes, definitely welcome changes. I'm still missing Bun's `$` shell functions though. It's very convenient to use JS as a scripting language and don't really want to run 2 runtimes on my server.
- adriancooney 1y agoYou might find your answer with `zx`: https://google.github.io/zx/ https://google.github.io/zx/
- denysonique 1y agoOr YavaScript https://github.com/suchipi/yavascript https://github.com/suchipi/yavascript
- turadg 1y agoExeca package works nicely for that. Zx has a good DX but is YA runtime. https://github.com/sindresorhus/execa/blob/main/docs/bash.md https://github.com/sindresorhus/execa/blob/main/docs/bash.md
- deleted 1y ago[deleted]
- HNMocksUsers 1y agoStarting a new project, I went with Deno after some research. The NPM ecosystem looked like a mess; and if Node's creator considers Deno the future and says it addresses design mistakes in Node, I saw no reason to doubt him.
- 1y ago
- nabwodahs 1y ago[dead]
- serguzest 1y agoOne thing you should add to section 10 is encouraging people to pass `cause` option while throwing new Error instances. For example new Error("something bad happened", {cause:innerException})
- upcoming-sesame 1y agoCool didn't know about this
- seniorsassycat 1y agoIt's wild that that's not what the section is about. Extending error is not new at-all.
- serguzest 1y agoMost people (including the author apparently) don't know they can chain errors with cause option in-built way in node and in browser. It is not just arbitrary extending and it is relatively a new thing. https://nodejs.org/api/errors.html#errorcause https://nodejs.org/api/errors.html#errorcause
- seniorsassycat 1y agoI've found that a lot of logging frameworks and patterns will not include cause which can absolutely fuck debugging
- fleebee 1y agoNice post! There's a lot of stuff here that I had no idea was in built-in already. I tried making a standalone executable with the command provided, but it produced a .blob which I believe still requires the Node runtime to run. I was able to make a true executable with postject per the Node docs[1], but a simple Hello World resulted in a 110 MB binary. This is probably a drawback worth mentioning. Also, seeing those arbitrary timeout limits I can't help but think of the guy in Antarctica who had major headaches about hardcoded timeouts.[2] [1]: https://nodejs.org/api/single-executable-applications.html https://nodejs.org/api/single-executable-applications.html [2]: https://brr.fyi/posts/engineering-for-slow-internet https://brr.fyi/posts/engineering-for-slow-internet
- llimllib 1y agoI have a blog post[1] and accompanying repo[2] that shows how to use SEA to build a binary (and compares it to bun and deno) and strip it down to 67mb (for me, depends on the size of your local node binary). [1]: https://notes.billmill.org/programming/javascript/Making_a_single-file_executable_with_node_and_esbuild.html https://notes.billmill.org/programming/javascript/Making_a_s... [2]: https://github.com/llimllib/node-esbuild-executable#making-a-single-file-executable-with-node-and-esbuild https://github.com/llimllib/node-esbuild-executable#making-a...
- sgarland 1y ago> 67 MB binary I hope you can appreciate how utterly insane this sounds to anyone outside of the JS world. Good on you for reducing the size, but my god…
- refulgentis 1y agoThe LLM made this sound so epic: "The node: prefix is more than just a convention—it’s a clear signal to both developers and tools that you’re importing Node.js built-ins rather than npm packages. This prevents potential conflicts and makes your code more explicit about its dependencies."
- wavemode 1y agoso in other words, it's a convention
- Hackbraten 1y agoAlso no longer having to use an IIFE for top-level await is allegedly a „game changer.“
- deleted 1y ago[deleted]
- bashtoni 1y agoAgreed. It's surprising to see this sort of slop on the front page, but perhaps it's still worthwhile as a way to stimulate conversation in the comments here?
- refulgentis 1y agoI have an increasing feeling of doom re: this. The forest is darkening, and quickly. Here, I'd hazard that 15% of front page posts in July couldn't pass a "avoids well-known LLM shibboleths" check. Yesterday night, about 30% of my TikTok for you page was racist and/or homophobic videos generated by Veo 3. Last year I thought it'd be beaten back by social convention. (i.e. if you could showed it was LLM output, it'd make people look stupid, so there was a disincentive to do this) The latest round of releases was smart enough, and has diffused enough, that seemingly we have reached a moment where most people don't know the latest round of "tells" and it passes their Turing test., so there's not enough shame attached to prevent it from becoming a substantial portion of content. I commented something similar re: slop last week, but made the mistake of including a side thing about Markdown-formatting. Got downvoted through the floor and a mod spanking, because people bumrushed to say that was mean, they're a new user so we should be nicer, also the Markdown syntax on HN is hard, also it seems like English is their second language. And the second half of the article was composed of entirely 4 item lists.
- asgr 1y agoDeno has sandboxing tho
- FearTheFacts 1y ago[dead]
- serguzest 1y agoI love Node's built-in testing and how it integrates with VSCode's test runner. But I still miss Jest matchers. The Vitest team ported Jest matchers for their own use. I wish there were a similar compatibility between Jest matchers and Node testing as well.
- tkzed49 1y agoassertions in node test feel very "technically correct but kind of ugly" compared to jest, but I'll use it anyway
- serguzest 1y agoyes but consider this Jest code, replicating such in node testing is painful. testing code should be DSL-like, should be very easy to read. expect(bar).toEqual( expect.objectContaining({ symbol: `BTC`, interval: `hour`, timestamp: expect.any(Number), o: expect.any(Number), h: expect.any(Number), l: expect.any(Number), c: expect.any(Number), v: expect.any(Number) }) );
- vinnymac 1y agoCurrently for very small projects I use the built in NodeJS test tooling. But for larger and more complex projects, I tend to use Vitest these days. At 40MBs down, and most of the dependency weight falling to Vite (33MBs and something I likely already have installed directly), it's not too heavy of a dependency.
- serguzest 1y agoIt is based on vite and a bundler has no place in my backend. Vite is based on roll-up, roll-up uses some other things such as swc. I want to use typescript projects and npm workspaces which vite doesn't seem to care about.
- deleted 1y ago[deleted]
- austin-cheney 1y agoI see two classes of emerging features, just like in the browser: 1. new technologies 2. vanity layers for capabilities already present It’s interesting to watch where people place their priorities given those two segments
- deleted 1y ago[deleted]
- insin 1y ago"SlopDetector has detected 2 x seamlessly and 7 x em-dash, would you like to continue?"
- Lockal 1y agoScreaming "you’re not just writing contemporary code—you’re building applications that are more maintainable, performant, and aligned"
- presentation 1y agofwiw i use em-dashes
- xdennis 1y agoI did too. :( I had to stop using them after people started assuming only LLMs use them.
- wiseowise 1y agoI use em-dash these days just to trigger tinfoil hats like you.
- deleted 1y ago[deleted]
- vinnymac 1y agoYou no longer need to install chalk or picocolors either, you can now style text yourself: `const { styleText } = require('node:util');` Docs: https://nodejs.org/api/util.html#utilstyletextformat-text-options https://nodejs.org/api/util.html#utilstyletextformat-text-op...
- austin-cheney 1y agoI never needed those. I would just have an application wide object property like: text: { angry : "\u001b[1m\u001b[31m", blue : "\u001b[34m", bold : "\u001b[1m", boldLine : "\u001b[1m\u001b[4m", clear : "\u001b[24m\u001b[22m", cyan : "\u001b[36m", green : "\u001b[32m", noColor : "\u001b[39m", none : "\u001b[0m", purple : "\u001b[35m", red : "\u001b[31m", underline: "\u001b[4m", yellow : "\u001b[33m" } And then you can call that directly like: `${vars.text.green}whatever${vars.text.none}`;
- tkzed49 1y agoI think the widely-implemented terminal escape sequences are well-known at this point, but I don't see why I'd want to copy this into every project. Also, I'm guessing if I pipe your logs to a file you'll still write escapes into it? Why not just make life easier?
- bravesoul2 1y agoAnyone else find they discover these sorts of things by accident. I never know when a feature was added but vague ideas of "thats modern". Feels different to when I only did C# and you'd read the new language features and get all excited. In a polyglot world and just the rate even individual languages evolve its hard to keep up! I usually learn through osmosis or a blog post like this (but that is random learning).
- moralestapia 1y agoI'm truly a fan of node (and V8) so once in a while (2-3 months?) I read their release notes and become aware of these things. Sometimes I also read the proposals, https://github.com/tc39/proposals https://github.com/tc39/proposals I really want the pipeline operator to be included.
- xbbdbd 1y agoReading release notes would have solved that issue ;)
- bravesoul2 1y agoWhich release notes. Id need to read hundreds!
- amadeuspagel 1y agoMaybe there's an idea in here, a website that shows you all release notes since the last time you've used something, removing those that have been superseeded by later ones, ranked by importance.
- Klaster_1 1y agoI recommend an excellent Node weekly [0] newsletter for all the things Node. It's been a reliable source of updates for over ten years. [0] https://nodeweekly.com https://nodeweekly.com
- panzi 1y agoUnless it changed how NodeJS handles this you shouldn't use Promise.all(). Because if more than one promise rejects then the second rejection will emit a unhandledRejection event and per default that crashes your server. Use Promise.allSettled() instead.
- vinnymac 1y agoPromise.all() itself doesn't inherently cause unhandledRejection events. Any rejected promise that is left unhandled will throw an unhandledRejection, allSettled just collects all rejections, as well as fulfillments for you. There are still legitimate use cases for Promise.all, as there are ones for Promise.allSettled, Promise.race, Promise.any, etc. They each serve a different need. Try it for yourself: > node > Promise.all([Promise.reject()]) > Promise.reject() > Promise.allSettled([Promise.reject()]) Promise.allSettled never results in an unhandledRejection, because it never rejects under any circumstance.
- mijkal 1y agoWhen using Promise.all(), it won't fail entirely if individual promises have their own .catch() handlers.
- andrewmcwatters 1y agoSubtle enough you’ll learn once to not do that again if you’re not looking for that behavior.
- kaoD 1y agoThis didn't feel right so I went and tested. process.on("uncaughException", (e) => { console.log("uncaughException", e); }); try { const r = await Promise.all([ Promise.reject(new Error('1')), new Promise((resolve, reject) => { setTimeout(() => reject(new Error('2'), 1000)); }), ]); console.log("r", r); } catch (e) { console.log("catch", e); } setTimeout(() => { console.log("setTimeout"); }, 2000); Produces: alvaro@DESKTOP ~/Projects/tests $ node -v v22.12.0 alvaro@DESKTOP ~/Projects/tests $ node index.js catch Error: 1 at file:///C:/Users/kaoD/Projects/tests/index.js:7:22 at ModuleJob.run (node:internal/modules/esm/module_job:271:25) at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:547:26) at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:116:5) setTimeout So, nope. The promises are just ignored.
- MuffinFlavored 1y agoIs current node.js a better language than .NET 6/7/8/9, why or why not?
- bloomca 1y agoNode.js is a runtime, not a language. It is quite capable, but as per usual, it depends on what you need/have/know, ASP.NET Core is a very good choice too.
- MuffinFlavored 1y ago> ASP.NET Core is a very good choice too. I have found this to not be true.
- jiggawatts 1y agoRecently? In my experience ASP.NET 9 is vastly more productive and capable than Node.js. It has a nicer developer experience, it is faster to compile, faster to deploy, faster to start, serves responses faster, it has more "batteries included", etc, etc... What's the downside?
- drewbitt 1y agoCompile speed and a subjective DX opinion are very debatable. The breadth of npm packages is a good reason to use node. It has basically everything.
- jiggawatts 1y agoIt has terrible half-completed versions of everything, all of which are subtly incompatible with everything else. I regularly see popular packages that are developed by essentially one person, or a tiny volunteer team that has priorities other than things working. Something else I noticed is that NPM packages have little to no "foresight" or planning ahead... because they're simply an itch that someone needed to scratch. There's no cohesive vision or corporate plan as a driving force, so you get a random mish-mash of support, compatibility, lifecycle, support, etc... That's fun, I suppose, if you enjoy a combinatorial explosion of choice and tinkering with compatibility shims all day instead of delivering boring stuff like "business value".
- lightbendover 1y ago[dead]
- NackerHughes 1y agoBe honest. How much of this article did you write, and how much did ChatGPT write?
- Our_Benefactors 1y agoWhat, surely you’re not implying that bangers like the following are GPT artifacts!? “The changes aren’t just cosmetic; they represent a fundamental shift in how we approach server-side JavaScript development.”
- jameshart 1y agoAnd now we need to throw the entire article out because we have no idea whether any of these features are just hallucinations.
- drewbitt 1y agoI think we have enough node developers here to know its truthfulness.
- JoshuaDavid 1y agoI'm not sure - a lot of the top comments are saying that this article is great and they learned a lot of new things. Which is great, as long as the things they learned are true things.
- int_19h 1y agoYou don't know if the author knows what they're talking about with or without AI in the picture.
- jameshart 1y agoTrue! But writing an egregiously erroneous blogpost used to take actual effort. The existence of a blogpost was a form of proof of work that a human at least thought they knew enough about a topic to write it down and share it. Now the existence of this blogpost is only evidence that the author has sufficient AI credits they are able to throw some release notes at Claude and generate some markdown, which is not really differentiating.
- growbell_social 1y agoI'm just happy to see Node.js patterns as a #1 on HN after continually being dismissed from 2012-2018.
- int_19h 1y agoBetween browsers and Electron, even those of us who hate this ecosystem are forced to deal with it, and if one does, at least one can do it with slightly more comfort using the newer tooling.
- nikanj 1y agoBy the time you finish reading this guide and update your codebase, the state-of-the-art JS best practices have changed at least twice
- ale 1y agoWhy bother with node when bun is a much better alternative for new projects?
- retired_account 1y agoWhy bother with bun when deno 2 is a much better alternative for new projects?
- 0x073 1y agoWhy bother with deno 2 when node 22 is a much better alternative for new projects? (closing the circle)
- crabmusket 1y agoI am being sincere and a little self deprecating when I say: because I prefer Gen X-coded projects (Node, and Deno for that matter) to Gen Z-coded projects (Bun). Bun being VC-backed allows me to fig-leaf that emotional preference with a rational facade.
- DimmieMan 1y agoI think I kind of get you, there's something I find off putting about Bun like it's a trendy ORM or front end framework where Node and Deno are trying to be the boring infrastructure a runtime should be. Not to say Deno doesn't try, some of their marketing feels very "how do you do fellow kids" like they're trying to play the JS hype game but don't know how to.
- crabmusket 1y agoYes, that's it. I don't want a cute runtime, I want a boring and reliable one. Deno has a cute mascot, but everything else about it says "trust me, I'm not exciting". Ryan Dahl himself also brings an "I've done his before" pedigree.
- FearTheFacts 1y ago
- simonw 1y agoWhoa, I didn't know about this: # Run with restricted file system access node --experimental-permission \ --allow-fs-read=./data --allow-fs-write=./logs app.js # Network restrictions node --experimental-permission \ --allow-net=api.example.com app.js Looks like they were inspired by Deno. That's an excellent feature. https://docs.deno.com/runtime/fundamentals/security/#permissions https://docs.deno.com/runtime/fundamentals/security/#permiss...
- kijin 1y agoPath restrictions look simple, but they're very difficult to implement correctly. PHP used to have (actually, still has) an "open_basedir" setting to restrict where a script could read or write, but people found out a number of ways to bypass that using symlinks and other shenanigans. It took a while for the devs to fix the known loopholes. Looks like node has been going through a similar process in the last couple of years. Similarly, I won't be surprised if someone can use DNS tricks to bypass --allow-net restrictions in some way. Probably not worth a vulnerability in its own right, but it could be used as one of the steps in a targeted attack. So don't trust it too much, and always practice defense in depth!
- int_19h 1y agoLast time a major runtime tried implementing such restrictions on VM level, it was .NET - and it took that idea from Java, which did it only 5 years earlier. In both Java and .NET VMs today, this entire facility is deprecated because they couldn't make it secure enough.
- arccy 1y agoI believe that the various OSes have implemented appropriate syscalls such as openat to support it e.x. https://go.dev/blog/osroot https://go.dev/blog/osroot
- kijin 1y agoEven that doesn't protect you from bind mounts. The rationale seems to be that only root can create bind mounts. But guess what, unprivileged users can also create all sorts of crazy mounts with fuse. The whole idea of a hierarchical directory structure is an illusion. There can be all sorts of cross-links and even circular references.
- rvz 1y agoPerhaps the technology that you are using is loaded with hundreds of foot-guns if you have to spend time on enforcing these patterns. Rather than taking the logical focus on making money, it is wasting time on shuffling around code and being an architecture astronaut with the main focus on details rather than shipping. One of the biggest errors one can make is still using Node.js and Javascript on the server in 2025.
- palmfacehn 1y agoJS on the backend was arguably an even bigger mistake when the JS ecosystem was less sophisticated. The levels of duct tape are dizzying. Although we might go back even further and ask if JS was also a mistake when it was added to the browser. I often wonder about a what-if, alternate history scenario where Java had been rolled out to the browser in a more thoughtful way. Poor sandboxing, the Netscape plugin paradigm and perhaps Sun's licensing needs vs. Microsoft's practices ruined it.
- nedt 1y ago> JS on the backend was arguably an even bigger mistake when the JS ecosystem was less sophisticated. I see it being used since over 25 years for the Austrian national broadcaster. Based at least originally on rhino, so it's also mixed with the Java you love. Fail to see the big issue as it's working just fine for such a long time.
- const_cast 1y agoThere's also many successful multi-natioksl banks built off of Cobalt. Cobalt was a mistake.
- wiseowise 1y agoWhat the f are you even talking about. It literally lists features modern Node.js has, there’s nothing to enforce.
- rvz 1y ago
- jmull 1y agoSomething's missing in the "Modern Event Handling with AsyncIterators" section. The demonstration code emits events, but nothing receives them. Hopefully some copy-paste error, and not more AI generated crap filling up the internet.
- yesbabyyes 1y agoIt's definitely ai slop. See also the nonsensical attempt to conditionally load SQLite twice, in the dynamic imports example. The list of features is nice, I suppose, for those who aren't keeping up with new releases, but IMO, if you're working with node and js professionally, you should know about most, if not all of these features.
- steve_adams_86 1y agoHasn't AsyncIterator been available in Node for several years? I used it extensively—I want to say—around 3 years ago. It's definitely awesome but doesn't seem newsworthy. The experimental stuff seems more along the lines of newsworthy.
- jay-barronville 1y ago> Hasn't AsyncIterator been available in Node for several years? I used it extensively—I want to say—around 3 years ago. Yes. It's been around and relatively stable in V8/Node.js for years now.
- jappgar 1y ago(Async) Iterators are definitionally pull-based and not suitable for event (push) handling. They've also been around for years as another poster mentioned.
- FearTheFacts 1y ago[dead]
- stevage 1y agoHuh, I write a fair bit of Node and there was a lot new here for me. Like the built in test stuff. Also hadn't caught up with the the `node:` namespace.
- didip 1y agoWill node one day absorb Typescript and use it as default?
- fud101 1y agoI could never get into node but i've recently been dabbling with bun which is super nice. I still don't think i'll give node a chance but maybe i'm missing out.
- mythz 1y agoGood to see Node is catching up although Bun seems to have more developer effort behind it so I'll typically default to Bun unless I need it to run in an environment where node is better for compatibility.
- zacharyvoase 1y agowe cannot escape the AI generated slop can we? online writing before 2022 is the low-background steel of the information age. now these models will all be training on their own output. what will the consequences be of this?
- throwaway-0001 1y agoI think top level async is bad because won’t converge with js browser. Node test also I dont think is great, because in isomorphic apps you’ll have 2 syntax for testing. I think the permissions are the core thing we should do, even if we run the apps in docker/dev containers. Aliases is nice, node:fetch but I guess will break all isomorphic code.
- fastball 1y agoTop-level async (I assume you mean `await`) is available in browsers. https://caniuse.com/?search=top%20level%20await https://caniuse.com/?search=top%20level%20await
- bilalq 1y agoI really wish ESM was easier to adopt. But we're halfway through 2025 and there are still compatibility issues with it. And it just gets even worse now that so many packages are going ESM only. You get stuck having to choose what to cut out. I write my code in TS using ESM syntax, but still compile down to CJS as the build target for my sanity. In many ways, this debacle is reminiscent of the Python 2 to 3 cutover. I wish we had started with bidirectional import interop and dual module publications with graceful transitions instead of this cold turkey "new versions will only publish ESM" approach.
- capt_obvious_77 1y agoCan you elaborate on the compatibility issues you ran into, with ESM, please? Are they related to specific libs or use-cases?
- plopz 1y agoThe two I find most annoying Hoisting/import order especially when trying to mock tests. Whether or not to include extensions, and which extension to use, .js vs .ts.
- hollowturtle 1y agoBun proved both worlds can work together, the mess is all on the Node.js shoulder, and we, the devs, are blamed for not adopting
- latchkey 1y agoMy modern node.js pattern is to install bun now.
- mavelikara 1y agoDoes the built-in test executor collect and report test coverage?
- imetatroll 1y agoThe constant churn.
- phendrenad2 1y agoJavascript is missing some feature that will take it to the next level, and I'm not sure what it is. Maybe it needs a compile-time macro system so we have go full Java and have magical dependency injection annotations, Aspect-Oriented-Programming, and JavascriptBeans (you know you want it!). Or maybe it needs to go the Ruby/Python/SmallTalk direction and add proper metaprogramming, so we can finally have Javascript on Rails, or maybe uh... Djsango?
- eric-burel 1y agoHi, regarding streams interoperability I've documented how to handle file streams a while ago, after experimenting with Next.js old system (Node.js based) and new system (web based) : https://www.ericburel.tech/blog/nextjs-stream-files#2024-update-one-liner-solution https://www.ericburel.tech/blog/nextjs-stream-files#2024-upd.... It sums up as "const stream = fileHandle.readableWebStream()" to produce a web stream using Node.js fs, rather than creating a Node.js stream.
- hollowturtle 1y agoAm I the only one believing common js was super ok and don't like esm? Or put differently I didn't see the necessity of having esm at all in Node. Let alone the browser, imagine loading tons of modules over the wire instead of bundle them
- gregoriol 1y agoYou can still bundle them, maybe you even should. Webpack still does a good job. Can also remove unused parts.
- hollowturtle 1y agoIf anything bun proves that both worlds can go together despite what proponents of web standards says
- jay-barronville 1y ago> If anything bun proves that both worlds can go together despite what proponents of web standards says Sure, but Bun's implementation is a confusing mess a lot of times. I prefer them separate. Note: This is no shade toward Bun. I'm a fan of Bun and the innovative spirit of the team behind it.
- spixy 1y agoYes. Also CommonJS does not support tree shaking.
- hollowturtle 1y agoNor does ESM if you import * as. Plus I believe it can be made to support tree shaking Edit: the proof my point reside in the many libraries which have an open issue because, even if ESM, they don't support tree shaking
- WorldMaker 1y ago
- valenterry 1y agoAs a primary backend developer, I want to add my two cents: > Top-Level Await: Simplifying Initialization This feels absolutely horrible to me. There is no excuse for not having a proper entry-point function that gives full control to the developer to execute everything that is needed before anything else happens. Such as creating database connections, starting services and connecting to APIs, warming up caches and so on. All those things should be run (potentially concurrent). Until this is possible, even with top-level await, I personally have to consider node.js to be broken. > Modern Testing with Node.js Built-in Test Runner Sorry, but please do one thing and do it well. > Async/Await with Enhanced Error Handling I wish had JVM-like logging and stack traces (including cause-nesting) in node.js... > 6. Worker Threads: True Parallelism for CPU-Intensive Tasks This is the biggest issue. There should be really an alternative that has builtin support for parallelism that doesn't force me to de/serialize things by hand. --- Otherwise a lot of nice progress. But the above ones are bummers.
- deleted 1y ago[deleted]
- joaohaas 1y agotry { // Parallel execution of independent operations const [config, userData] = await Promise.all([ readFile('config.json', 'utf8'), fetch('/api/user').then(r => r.json()) ]); ... } catch (error) { // Structured error logging with context ... } This might seem fine at a glance, but a big grip I have with node/js async/promise helper functions is that you can't differ which promise returned/threw an exception. In this example, if you wanted to handle the `config.json` file not existing, you would need to somehow know what kind of error the `readFile` function can throw, and somehow manage to inspect it in the 'error' variable. This gets even worse when trying to use something like `Promise.race` to handle promises as they are completed, like: const result = Promise.race([op1, op2, op3]); You need to somehow embed the information about what each promise represents inside the promise result, which usually is done through a wrapper that injects the promise value inside its own response... which is really ugly.
- SebastianKra 1y agoIMO when you do control-flow in catch blocks, you're fighting against the language. You lose Typescripts type-safety, and the whole "if e instanceof ... else throw e"-dance creates too much boilerplate. If the config file not existing is a handleable case, then write a "loadConfig" function that returns undefined.
- augusto-moura 1y agoYou are probably looking for `Promise.allSettled`[1]. Which, to be fair, becomes quite convulated with destructuring (note that the try-catch is not necessary anymore, since allSettled doesn't "throw"): // Parallel execution of independent operations const [ { value: config, reason: configError }, { value: userData, reason: userDataError }, ] = await Promise.allSettled([ readFile('config.json', 'utf8'), fetch('/api/user').then(r => r.json()) ]); if (configError) { // Error with config } if (userDataError) { // Error with userData } When dealing with multiple parallel tasks that I care about their errors individually, I prefer to start the promises first and then await for their results after all of them are started, that way I can use try catch or be more explicit about resources: // Parallel execution of independent operations const configPromise = readFile('config.json', 'utf8') const userDataPromise = fetch('/api/user').then(r => r.json()) let config; try { config = await configPromise } catch (err) { // Error with config } let userData; try { userData = await userDataPromise } catch (err) { // Error with userData } Edit: added examples for dealing with errors with allSettled [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- wildpeaks 1y agoMost importantly, Node has Typescript support even in LTS (starting with v22.18). I highly recommend the `erasableSyntaxOnly` option in tsconfig because TS is most useful as a linter and smarter Intellisense that doesn't influence runtime code: https://www.typescriptlang.org/tsconfig/#erasableSyntaxOnly https://www.typescriptlang.org/tsconfig/#erasableSyntaxOnly
- theozero 1y agoFor a more modern approach to .env files that includes built-in validation and type-safety, check out https://varlock.dev https://varlock.dev Instead of a .env.example (which quickly gets out of date), it uses a .env.schema - which contains extra metadata as decorator comments. It also introduces a new function call syntax, to securely load values from external sources.
- juuuk 1y agok
- juuuk 1y agovb
- juuuk 1y agowhat that