{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreicqqz2guyzjljf5wrt64oa4ucesrzegfqnl44v7sfvlnloirbpbku",
"uri": "at://did:plc:wf5p6xnpnvp7jeg5htba4j4z/app.bsky.feed.post/3mnrscvc7ldi2"
},
"path": "/@hongminhee/2026/i-wish-deno-would-keep-doing-what-it-does-best",
"publishedAt": "2026-06-08T13:30:42.348Z",
"site": "https://hackers.pub",
"tags": [
"Deno",
"Node.js",
"Node",
"TypeScript",
"JavaScript",
"Deno가 자신이 가장 잘하는 것을 계속해 나가길 바란다",
"TypeScript runs without flags as of v22.",
"A permission model arrived in v20.",
"fetch()",
"Web Crypto API",
"node:test",
"node:assert/strict",
"2.4",
"Fresh 2.0, Deno's own framework, chose not to fill that gap from within Deno and adopted Vite instead."
],
"textContent": " * 한국어 (Korean):\n * 한국어(대한민국) (Korean (South Korea)): Deno가 자신이 가장 잘하는 것을 계속해 나가길 바란다\n\n\n\n* * *\n\n## The wall of configuration\n\nFor years I worked in Python and dreamed in Haskell on weekends. When I needed a script, Python. When I wanted the type system to hold me accountable, Haskell. Somewhere between the two sat TypeScript, and I knew it. Practical where Haskell is austere, typed where Python isn't. But I kept my distance. _tsconfig.json_ , _.eslintrc_ , _.prettierrc_ , _babel.config.js_. Files you have to create before you've written a single line of actual code. Every time I thought about trying it, I looked at the list and gave up. The JavaScript ecosystem always felt to me like an amusement park where you have to wait in a long queue just to get inside.\n\nDeno dissolved that queue. No configuration files, no _node_modules_ , no agonizing over which package manager to use. Just `deno run main.ts`. The first time I actually wrote TypeScript properly, I couldn't understand why I'd put it off so long. What I'd been avoiding wasn't TypeScript. It was the ritual surrounding TypeScript.\n\n## What hooked me\n\nAt first I couldn't point to one killer feature. The appeal was that everything seemed to be pulling in the same direction. The `fetch()` I used in browsers worked the same way on the server. Web Crypto API was just there. MDN effectively became Deno's documentation. Instead of installing packages, you imported ESM by URL, thinking about dependencies in an entirely different way.\n\nHaving `deno fmt`, `deno lint`, `deno test`, `deno bench`, and `deno check` all in a single binary was part of the same logic. No installing ESLint, no wiring up Prettier, no untangling configuration conflicts between the two. That convenience had an attitude behind it.\n\nThe pattern was obvious enough: build on web standards, then ship the boring tools yourself.\n\n## Chasing Node.js\n\nToday's Deno feels like it's drifting away from that.\n\n`npm:` specifier support, _node_modules_ back in play, `node:*` module compatibility. Then in Deno 2.8, `deno add` without a specifier now adds an npm package by default. JSR was introduced as an answer to npm's stagnation, as the future of JavaScript packaging. These decisions make that announcement look distant. I can understand each one in isolation. Put them together, though, and the shape is hard to ignore: Deno is spending more and more of its energy catching up to Node.js.\n\nThe OS/2 story comes to mind. IBM expected that building Windows compatibility into OS/2 would pull Windows users across. What actually happened was the opposite: developers realized they could target Windows and have it run on both platforms, so there was no reason to learn the OS/2 API separately. Deno pushing further toward Node.js compatibility has the same dynamic. The more compatible Deno becomes, the less reason library authors have to think about it specifically.\n\nMeanwhile, Node.js has been walking toward Deno. TypeScript runs without flags as of v22. A permission model arrived in v20. fetch() and Web Crypto API are both there now. node:test and node:assert/strict have quietly become the best cross-runtime test harness for projects targeting Deno, Node.js, and Bun alike. The two runtimes are converging, but Deno seems to be doing more of the reaching.\n\nEarly Deno set the agenda. Web standards, the permission model, URL imports, JSR: Deno put these down and the ecosystem responded. What Deno is doing now runs in the opposite direction, catching up to what the ecosystem already has.\n\n## On the defensive\n\nThere's a more specific frustration here. Deno had a fight it could have led rather than chased.\n\nWhat drove me away from the JavaScript ecosystem wasn't Node.js itself. It was the full combination: Node.js + npm + TypeScript + Vite + ESLint + Prettier + Vitest. That stack was the problem, and Deno was already doing well against it. `deno fmt`, `deno lint`, `deno test`, `deno bench`, `deno check`, and in 2.4, `deno bundle` came back. It had been deprecated once and then restored; that round trip is its own admission that the direction was right.\n\nThe most visible gap that remains is the dev server: HMR, live reload, an asset pipeline, and the plugin ecosystem that accumulates on top of all that. Fresh 2.0, Deno's own framework, chose not to fill that gap from within Deno and adopted Vite instead. That disappointed me. Making Vite run well on Deno and making Deno a self-sufficient development environment are two entirely different directions. Once your own framework makes that choice, you can't expect the wider ecosystem to go the other way.\n\nBut vertical integration alone might not have been enough. Individual component quality matters too. If `deno lint` and `deno fmt` were clearly better than ESLint and Prettier, developers would reach for them even in Node.js projects. That could have been the Trojan horse. Once enough projects are using Deno's tools without using the Deno runtime, the next question follows naturally. ESLint and Prettier seemed unmovable, and yet Biome and the Ox series (Oxlint, Oxfmt) are finding their footing. The market was always there. Better tools just weren't. Deno could have gotten there first.\n\n## The clock I keep thinking about\n\nWhy didn't Deno hold the course? This is speculation, but here's my read.\n\nThe integrated toolchain path required patience. Getting developers to feel the pain of configuration complexity, making Deno the place they move to, waiting for the ecosystem to grow comfortable with Deno's way of doing things. All of that takes time. Node.js is a community project under the OpenJS Foundation. There's no investor clock pushing it, and the project doesn't wobble if the ecosystem moves slowly.\n\nDeno Land Inc. is different. A VC-backed company has a clock. How long that clock allows for a patient fight is not the same as what a community project can afford. Expanding Node.js compatibility produces visible results faster than the slow alternative. From the outside, I can't tell when I'm seeing a product decision and when I'm seeing a runway decision. What I can say is that the urgency Deno has been showing doesn't sit well with the direction it originally chose.\n\n## Even so\n\nFor all my griping, I still build most of my own libraries Deno-first. I publish to JSR even when I also publish to npm. I try to depend only on web standard APIs, and I use Deno's built-in tools for linting and formatting. I'm still rooting for Deno.\n\nBut even I have retreated in places. I now rely on node:test and node:assert/strict for testing, because it's the easiest way to run the same tests across Deno, Node.js, and Bun without any special dependencies. JSR was launched as an answer to npm's stagnation, and I've started to feel JSR stagnating too. I often catch myself wondering whether to drop it. I got excited about Deno KV and now I just use `node:sqlite`, which runs fine on Deno anyway.\n\nIf someone like me is already making these retreats, I wonder what Deno looks like to someone with no attachment to it at all. That worries me, because I still want Deno to win some version of this fight. I'm just less sure lately that Deno wants to win the same fight I signed up for.",
"title": ""
}