We just finished scoping another greenfield web application. It will ship on Node.js — specifically Nuxt and Vue on the front, a Node service in the middle, MySQL at the back. Most of our new web work over the past year has gone that way. Every time we make that call, a small voice in the back of the room wonders whether it is inertia rather than judgement.
This post is an honest answer to that question, from a small Bulgaria-based shop that still reaches for Node.js most of the time — and a deliberate accounting of the places we do not.
The ecosystem compounds
Node.js did not win on language design. It won on ecosystem.
Every year since around 2018, the same dynamic has compounded. TypeScript has caught up with static languages in the spots that matter for our kind of work. Vite has made the dev loop faster than we thought was possible a few years ago. Nuxt and Next have stabilised into frameworks you can bet a three-year engagement on. And the npm ecosystem keeps expanding past the point where other languages can realistically match it.
Concretely: when a client asks us to scope a new dashboard, we can reach for the same stack we used on a marketing site last month. The engineers we assign do not need to context-switch. The CI pipeline we used on the last several projects carries over with minor adjustments. The hosting setup is familiar. Each of those things is a day of work we do not have to spend on each new project.
That compounding is easy to dismiss on a spec sheet and hard to beat in practice.
What we tried and stepped back from
We are not religious about Node. Over the years we have put real work on other stacks — and, in a few cases, started there before moving.
Go. We like Go a lot. It compiles fast, runs fast, and deploys as a single binary, which is hard to argue with. But Go's low-level strengths are wasted on the kind of web work we do most often — CRUD dashboards, CMS-driven sites, integration glue. A Node service reaches feature parity with less code, and the shared language across server and browser (TypeScript on both sides) cuts a class of bugs at the edge. We still reach for Go for a narrow slice of work: high-throughput services, small CLIs, or engagements where the client's existing team is already fluent.
Python. Python is a different shape. It is the right tool for data processing, image work, and anything that calls into a machine-learning model. It is less obviously the right tool for a long-lived web API — Python's web frameworks (Flask, FastAPI, Django) are all capable, but none of them match Nuxt or Next in day-to-day productivity for a full-stack build. Where a project has a real data or ML component, we still reach for Python — usually alongside a Node orchestration layer rather than replacing it.
PHP. PHP is the complicated one. We have shipped real PHP in the past eighteen months — Laravel applications and older WordPress installations that our clients rely on. For new greenfield work, we have moved on: PHP's ecosystem has not kept up with the iteration speed we get in JavaScript, and our engineers would rather keep their context in one language. But for an existing PHP client, rewriting is almost always the wrong answer, and we stay in the stack their code already lives in.
Where we still do not use Node
Three contexts where Node is the wrong pick, and we say so to clients up front:
Heavy data processing. When we are transforming significant volumes of data, batch-processing images, or touching any serious ML model, we reach for Python — or pass the work to tools designed for it. Node can technically do those things, but "technically" is not an argument we make to clients.
Existing WordPress and Laravel codebases. When a client's site is already on WordPress, the job is to keep it healthy — plugins, PHP version bumps, security patches — not to port it to Node because we prefer Node. A migration has to justify itself with real business reasons, not a stack preference.
Specialised needs. There are narrow domains — embedded, hard real-time, and certain cryptographic work — where Node is the wrong tool. We do not take on work in those areas unless we can do it well.
The boring answer
None of this is a pitch for Node.js. If the right answer in a given project is Laravel, we will build on Laravel. If it is Go, we will build on Go. The point is that for the specific shape of work we see most often — small and mid-sized European businesses asking for a web application that needs to be maintainable for several years by a small team — Node has won the fit-for-purpose argument for us, and keeps winning it project after project.
It is not the most exciting answer. But the most exciting stacks tend to be the ones that bite you in year two.
