Zoosh Cloud Native Software Development Logo
Zoosh Cloud Native Software Development Logo

Article

How the Node.js and React based open stack became mainstream (and why you should consider using it)

Gábor Tolnai
May 13, 2024

Frameworks, and even programming languages come and go. Of course evolving a framework, or moving to the next one is easier than moving on to a completely new language or platform, but languages do evolve, and it is worth to consider even adopting new languages. Of course Java, Python or .NET won’t go anywhere soon and there is no silver bullet, no perfect language which is above the others. Due to some combination of qualities, let’s explore why you should really consider using TypeScript besides or instead of the others.

What’s the right time for adopting a language or a new framework? There is a precious balance, since there is danger in both adapting too early (using so called “bleeding edge” technologies which are immature) or adapting too late (slowing down, missing out on new improvements and getting behind competition). We are in an interesting time, where it’s possible to actually use the same language in several different layers of a technical stack, and all of them are already becoming mainstream. This language is TypeScript.

A quick recap on TypeScript, the language behind

There are some languages tailored for special use cases, some others which just evolved over time but still keep their legacy with them. There are also some languages which are quite simple and generic and can be used in different environments.

JavaScript was THE language that can be run in browsers. As our desktop applications moved more and more into the browsers, JavaScript became widespread and popular. This resulted in a number of things:

  • Creating new frameworks, more and more mature and higher level
  • Pulling in the open-source community, popularity generating more and more ready-to-use components
  • JavaScript moving into other layers, especially into running from CLI
  • Microsoft realizing the potential, and evolving the JavaScript language into the TypeScript we know today

These various effects enhanced each other and the popularity exploded. The language is the most popular one on some recruitment sites already and in the first few in many reports.

The reason for that is two-fold. On one hand, with the type safety of TypeScript it’s not just for startups anymore but a valid choice for enterprises as well, and some other features of the language (listed in the next section) also make it compelling to developers and leaders alike. On the other hand, having the huge repository of existing open-source components and working across layers it can result in more cost-efficient development.

Why languages matter?

The language we use fundamentally defines some of the aspects of the development. Languages don’t just enable us to use existing components, but there are several consequences of their characteristics. Let’s explore some of them.

TypeScript is strongly typed. Having a strong type system (which for example Python doesn’t have) is crucial for trust in the code base. Types are the first line of defense, when it comes to quality assurance. Without having types, issues that could be captured when writing or building the code will only occur at run time, which can become a catastrophe. Types document the mental model of the application and can avoid a lot of errors while writing the code, as the compiler provides immediate feedback if something is not consistent. Interestingly, there is no “one single TypeScript”, it can be configured in different ways - and one needs to configure it strictly to get the most benefits.

TypeScript is flexible. The TypeScript language has been crafted to keep some of the flexibility of the original JavaScript, so it can be a really powerful tool. It doesn’t just provide simple OO (Object-Oriented) types like interfaces, classes or enums, but generics, annotations, union and intersection types, type guards, aliases, and so on. What one can achieve with TypeScript types may seem as magic for people used to old-school C or Java code (for example games implemented purely with types!).

TypeScript is convenient. There are many syntax sugar type of patterns that can be used for common problems (mostly coming from the underlying JavaScript), which reduce the code, but more importantly make the code more understandable and compact, resulting in developers being more efficient and focusing on adding value. (Just to name a few: async/await, optional chaining, nullish coalescing, spread operator, destructuring, template literals…) Some of these syntax sugars also did get introduced in Java or C#, but since TypeScript is evolving really fast, new and new additions are continuously released, pleasing developers.

TypeScript related tooling is open. With TypeScript, everything, including the tooling, can be replaced or customized. The result is not just a range of choices tailored for different scenarios (keeping the same language), but also rapid improvement in tooling. If someone doesn’t like the default package manager, they can use another one. There are different options to build and bundle the application, to run different types of tests, to run a spell checker against the code, automatically update dependencies, and so on.

Picking the right language can help with development speed, productivity, quality, employee/developer satisfaction and can impact the overall success of the product or system.

The business benefit of using the same language on the full stack

Having a strongly typed, flexible and convenient language, which gives freedom around tooling and which people love, is one thing. But allowing them to use the same flexibility, same freedom and same convenient features regardless of writing backend or frontend code is another level.

One could argue, that a language is “just a tool”, and that is true. But still, using the same syntax and similar structures across different applications improves productivity. It’s not just about not needing to learn a different language for the backend or frontend, but it opens the door to scaling full-stack development easier.

Developers can become productive quicker in new layers, and can jump easier between them. Full-stack capacity can be better utilized than separate backend and frontend teams (even if that separation could still make sense in some cases). It’s easier to operate a full-stack scrum team, as new tasks having different backend/frontend work ratio doesn’t jeopardize the utilization of the team. Code review can also happen quicker, having more people available to be reviewers, without the need of them being experts in several languages.

React Native takes this one step further, by allowing to use the same TypeScript, that developers are already familiar with, in mobile apps as well. Imagine the benefit of having universal developers, who can work on any parts of the system, without the need of hiring rockstars. (This can be a divisive topic but I will elaborate on this below.)

There are still ongoing movements in this space which could take this even further, evolution never stops. There are full-stack frontends emerging, where the backend and frontend is one single application, part of the code running on a server and some other part in the browser. (Don’t mistake it with being a monolith, as this pattern can still fit into the microservice approach, and let’s not even mention micro-frontends.) TypeScript can also be used to create desktop applications. It’s important to keep track of the evolution of the technology, and evaluate, if or when it’s worth to jump on a new trend.

Node.js with TypeScript - not just for hobby projects

The Node.js way of using JavaScript and TypeScript code in server environments can be considered completely mature. It is a stable platform with well established development and maintenance cycles. The popularity of Node.js is steady, even if there are competitors trying to challenge its place, like Deno (which is another JavaScript runtime environment, focusing on security and performance).

Node.js environments are supported natively by all major cloud providers, besides of course having good docker support as well. There are full, alpine and slim image variants available for smaller containers. Building and compiling applications is also supported by all major CI/CD pipeline tools. There are also tools such as SAST security tools, code analysis tools like Sonar, tools to measure code coverage, all the usual steps that keep a code base maintainable.

Node.js is only a runtime environment, not a framework. There are various frameworks that can be used, one of the most popular being Nest.js. Nest.js ticks all the boxes an enterprise would like to see in a framework: proper logging, dependency injection, separating modules, controller and service layers, ORM and various database connections, and of course it can be extended with practically anything from the available open source components.

There are other frameworks for other more tailored use cases, for example smaller frameworks for speed and productivity like FoalTS, frameworks built around an extended ORM like Prisma, or more complete headless systems: CMS (e.g. Keystone) or e-Commerce (e.g. Vendure) platforms, and many many more.

All in all, using TypeScript on Node.js means having the flexibility of this strongly typed language, a wide range of frameworks to get started with, and a vast collection of tools and components from the community to expedite development. There is no silver bullet, but in our experience this combination can perfectly fit most typical use cases. The only difficulty might be to be able to choose the right tools for the job to reduce the amount of experimentation, which some external help can expedite a lot.

Choosing React for the frontend

React and Node.js are typically mentioned together, even though they are not at the same level, since React is a framework on the frontend, while Node.js is just the runtime environment for the backend. The runtime environment on the frontend is the browser’s JavaScript engine, so it’s in the control of the end users. What matters on the frontend is the framework, and how the application is built and bundled.

Most developers consider React and Angular as the two main frameworks on the frontend. While we could also mention Vue and some others on this list, these two are definitely the most popular ones. They are really different though. Angular is a large framework, more enterprise grade with a lot more structure, while React is a relatively slim framework, defining the core principles on how to create the frontend but not having as much structure and as many features out of the box as Angular. Preferring one over the other is opinionated.

We still favor React over Angular because of the following reasons. React gives us more freedom on how we build the applications (which Angular is quite strict about), it has better component support (as the popularity of React surpassed Angular in the open-source community) and with the right mix of tools it can be considered just as mature and enterprise-ready as Angular. The caveat is that of course one needs to carefully pick the right components and to cook them into a tasty mix can be tricky initially. This can be sped up by using some of the more complete frameworks built around React and extending its functionality, for example RedwoodJS, Next.js or Remix.

Last but not least, one major advantage of having React in the stack can be the ease of conquering mobile as well by adding React Native to the mix.

TypeScript and React for mobile - with React Native

While React Native has been mentioned before, it’s worth to elaborate on it explicitly.

Choosing React as the frontend framework and having React Native based mobile development means that the same developers may be able to work on both. This is why choosing the React framework can be even more beneficial, on top of choosing TypeScript. React Native uses the same core principles, core React way of doing things, same hooks as React. However, apps built with it can appear and behave exactly like a native iOS/Android app (unlike some other cross-platform technologies like Ionic) due to how it’s compiled and combined with native packages.

It’s important to mention, that developing for the mobile still remains somewhat different and special, compared to web development. Layouts, styling, navigation, notifications (among other things) work differently on mobile, so having previous mobile development experience (native or React Native) does help a lot. It takes more time for a developer to become fully productive on the mobile compared to the backend or frontend, but React Native removes most of the difficulties and entry barriers for developers who are extending their range. Thus, making it much more available and affordable than other languages or frameworks for developers and companies alike. (Even more so, there are also frameworks built around React Native as well, one worth to mention is Expo.)

The React Native world has somewhat fewer available components than the backend/web world, but it’s already way beyond being “bleeding edge” and can be safely considered mature enough for enterprises and production use.

There is of course a place for true native iOS/Android apps, but in our experience React Native can be sufficient for most business cases. It’s cross-platform, so there is no need to create the same code twice for the two platforms which reduces the app development cost a lot. On top of that, it can have added benefits by utilizing the team better and not having (as many) dedicated mobile developers.

Summary

Having a development stack built around Typescript, using Node.js, React and React Native can be a really productive and efficient way of developing not just simple applications, but complex systems alike. Both the language and available frameworks are mature enough for production use, and with the right tooling and pipelines the same type of stability and quality assurance can be built around them as with other “traditional” languages and frameworks (like Java and Spring, .NET, etc.). But on top of this, they are built for flexibility and rapid development.

Having full-stack teams can improve their utilization and so the overall efficiency of the R&D. Teams can take full ownership of their own applications in a bigger system as well, without the need to have special language related skills in each team. Considering the popularity of the language and the frameworks it’s also relatively easy to find developers who are happy to work with these technologies.

There may be a fear of change, as existing R&D teams might resist on learning and moving on to something completely new. However, existing teams can also be upskilled by having them working together with external experts as augmented teams.