NexusHand
Engineering

Boring technology is a feature: our default stack, defended

6 min readNexusHand Engineering

The stack, stated plainly

TypeScript across the whole application, front and back. Next.js for anything with a user interface. NestJS for the API layer. PostgreSQL as the default database. Redis for caching, queues, and sessions. Deployment to a plain VPS or a mainstream cloud provider, not a bespoke platform assembled from a dozen managed services. Every product we operate ourselves, qCommerz included, runs on exactly this stack. That is deliberate, not an accident of what one client project happened to need. We are not choosing conservatively for other people's businesses while running something more adventurous underneath our own. It is also, not coincidentally, the stack most of our own hires already know on day one. None of it is unusual enough to make a conference talk. That is precisely the point.

What we are actually optimising for

None of these choices are about which technology is most interesting to work with. Four questions decide what makes the list:

  • Hiring pool: if an engineer leaves, can we find and onboard a competent replacement for this piece within weeks, not months, in Dhaka or anywhere else.
  • Documentation depth: is the answer to a hard question one search away, or does it live in a half-finished GitHub issue thread on a small, under-maintained project.
  • Ten-year survival: given its adoption and who governs it, will this project plausibly still be maintained a decade from now, or is it one maintainer's side project away from going quiet.
  • Escape hatches: when the framework's opinion is wrong for one specific case, can we drop to plain SQL, a manual script, or a raw request handler without rewriting the system around it.

TypeScript earns its place because catching a wrong field name or an unhandled null at compile time is cheaper than finding it in a production incident at two in the morning. Next.js earns its place because its rendering model is documented to exhaustion and the pool of developers who already know React is deep, in Bangladesh and everywhere else we hire from. NestJS gives Node.js actual structure, modules, dependency injection, a convention for where things live, without inventing a new language to get it. PostgreSQL earns its place through roughly three decades of being boring in exactly the way that matters: extensions like full-text search or row-level security are there to reach for later, instead of forcing a second database into the system before anyone has proven it is needed.

Redis earns its place the same way. It is one well-understood tool for caching, session storage, and lightweight queues, rather than three different specialised services for three different jobs. Fewer moving parts means fewer places an on-call engineer has to look at two in the morning, and a smaller set of tools that every new hire has to learn before they are useful.

The same reasoning extends to where things run. A plain VPS or a mainstream cloud provider, deployed with ordinary tools, means an incident at two in the morning can be debugged by connecting in and reading logs, not by learning a proprietary platform's dashboard under pressure for the first time. It is a deliberately unglamorous choice, and unglamorous is exactly what you want from infrastructure during an incident.

What we deliberately avoid at the MVP stage

A handful of technologies are genuinely good ideas that we still avoid until a project has earned them.

Microservices split a system into independently deployed services connected over a network. That buys real independence at the cost of a real tax: network calls where function calls used to be, distributed debugging, more moving parts to keep online. Two services means two deployments to coordinate, two sets of logs to correlate when something breaks, and a network call that can fail in ways a function call never does. Almost no early-stage product has the traffic or the team size to make that tax worth paying. A single, well-structured NestJS application is faster to build, easier to debug, and cheaper to operate until growth genuinely demands otherwise.

Event sourcing, storing every change as an immutable event rather than just the current state, is a good fit for domains that need a full audit trail as a first-class feature, financial ledgers being the clearest example. Building it before a team understands its actual read and write patterns usually means designing for a shape of problem being guessed at, not one that has been measured. For most products, an ordinary changelog table bolted onto the main schema gets most of the audit value at a fraction of the design cost.

Exotic databases, a graph database for relationships, a specialised time-series store for metrics, solve real problems, just rarely the problem an MVP actually has yet. Well-indexed PostgreSQL handles the large majority of early-stage workloads, including some that look at first glance like they need something more specialised. A specialised store is also a second thing to back up, secure, monitor, and keep a team trained on, costs that are easy to ignore while a system is small and expensive to discover once it is not.

We would reach for each of these once the evidence, not the enthusiasm, justifies it: microservices once a team is large enough that independent deploys reduce coordination cost rather than adding it; event sourcing when audit-as-a-feature is a genuine requirement, not a nice-to-have; a specialised datastore once a specific, measured bottleneck, search at a scale Postgres genuinely cannot hold, or true graph traversal queries, makes the case on its own.

Boring lowers the client's cost of ownership, not just ours

A stack chosen to make our own build faster or more interesting would be a bad trade if it left the client harder to serve after we handed the project over. TypeScript, Next.js, NestJS, and PostgreSQL are boring specifically because they are widely taught, widely hired for, and thoroughly documented, which means a client is not dependent on us specifically to keep their own product running. We hand over the full repository and documentation on final payment. A stack a stranger can pick up in a reasonable amount of time is what makes that handover mean something, rather than being a formality that quietly leaves the client stuck with us anyway. It also means a second opinion is always available: any competent engineer or agency can review this stack and tell a client honestly whether it was built well, because there is nothing proprietary or unusual standing between them and the code.

This matters even more once a client hires their own engineer, or brings the work in-house. A stack built from mainstream, well-documented tools means that hire is easy to find and quick to get productive. A stack built from whatever we personally found most interesting to use that year would quietly make the client dependent on us long after the invoice said the relationship was over.

Where the novelty budget actually goes

None of this means novelty is banned. It means it is rationed, and spent where a user can actually feel it rather than on infrastructure nobody but us will ever look at. qCommerz's onboarding, picking a template, adding products, connecting a domain, and being live in minutes, is where we spend that budget, because that flow is the product's real differentiation. The PostgreSQL database underneath it doing that job is unremarkable on purpose. The interesting, differentiated work is supposed to be visible to the person using the product, not buried in a novel choice of message queue that only we will ever see.

Every unfamiliar piece of infrastructure is a bet against whoever has to maintain this after us. Sometimes that is a client's next hire. Often, on our own products, it is future us.

Building something in this space?

A 30-minute call is enough to tell you honestly whether we're the right team for it — and what it will take.

Send project details