CMDN Radar: Our Tech Stack in 2024

Dmitry Zaets
Architecture & Engineering
December 1, 2023
Our Tech Stack in 2024

Our team invests considerable time in validating ideas and constructing MVPs. Therefore, establishing a robust tech stack is crucial for us. With the frequent initiation of new projects, we've had plenty of time to test various technologies in real-life scenarios, compare them, and select the ones that prove most effective for our needs.

In this article, we'll closely examine the stack our team uses to build MVPs and products for startups.

Here are the key criteria we prioritize when selecting technologies for our stack:

  • Fast Development: The chosen stack should facilitate fast development of new features.
  • Ease of Maintenance: It should be seamless to maintain existing features, ensuring long-term sustainability.
  • Scalability: The tech stack should easily scale to accommodate a growing user base.
  • Active Maintenance: Every framework and library should be actively maintained to avoid reliance on obsolete third-party technologies.
  • Recruitment Friendly: The stack should facilitate the recruitment of new team members with ease.
  • Comprehensive Documentation: A well-documented tech is essential for efficient development and troubleshooting processes.

To enhance clarity, we've assigned one of the following statuses to each technology:

  • ✅ Keep Using - We have a history of using it and plan to continue.
  • ❌ Stop Using - We've used it in existing projects but won't use it in new ones.
  • ▶️ Start Adoption - We haven't used it before but plan to integrate it into new projects.
  • ⏩ Keep Adoption - We recently started using it and will continue in new projects.
  • ⏸️ Wait with Adoption - We like the technology but believe it's too early to incorporate into our workflow.

AI Tools

This year marked significant growth in AI tooling, with our team exploring various new tools and products entering the market.

ChatGPT

We rely on ChatGPT for a wide range of tasks, from assisting in email composition to proofreading this article 😅.

Link: https://chat.openai.com
Status:
✅ Keep Using

GitHub Copilot

As one of the best AI-based developer tools available, GitHub Copilot has become an indispensable part of our workflow since mid-2023.

Link: https://github.com/features/copilot
Status:
✅ Keep Using

DALL·E 3

The latest version of DALL·E shows great promise, producing images that surpass its predecessor and outshine competitors.

Link: https://openai.com/dall-e-3
Status:
▶️ Start Adoption

Databases

The era when developers would default to using MongoDB without specific reasons, merely for its ease in prototyping, has passed. We have consistently avoided following trends and instead choose databases tailored to each project. In our experience, relational databases have often proven more effective for our needs.

PostgresSQL

As our primary database, we've used PostgreSQL in all our past projects, finding it well-suited for various setups.

Link: https://www.postgresql.org
Status: ✅
Keep Using

Infrastructure

We package our straightforward infrastructure into Docker images. As the complexity increases, we transition to using managed Kubernetes clusters.

Docker

Docker Image is the common way of delivering our services for both Backend and Frontend.

Link: https://www.docker.com
Status: ✅
Keep Using

Hosting

We typically opt for hosting solutions that align with our clients' preferences. Many startups qualify for the Startup Programs offered by major cloud providers such as AWS, Google Cloud, Microsoft Azure, Oracle Cloud, etc. However, if a client is unwilling or unable to secure credits through these programs, we suggest a straightforward and user-friendly alternative that can be easily managed and understood, even by individuals without technical expertise.

Digital Ocean

Digital Ocean stands out as a simple and elegant hosting provider that caters to various clients. We've successfully hosted projects entirely on Digital Ocean, ranging from basic Staging environments with minimal resource consumption to self-scaling Production environments. This includes features such as database replication, regular backups, and other essentials for startups at every step of their early stage.

Link: https://www.digitalocean.com
Status: ✅
Keep Using


Payments

Managing payments is a crucial aspect of every SaaS platform, and ensuring a swift and straightforward method for online transactions is a priority for us.

Stripe

We rely on Stripe to handle both individual payments and subscriptions. It offers support for various features, including coupon codes, invoice generation, and other functionalities essential for SaaS platforms.

Link: https://stripe.com
Status: ✅
Keep Using

Email templates

Effective email communication is integral to any modern web application, and after experimenting with various solutions, we've settled on the choices we currently use.

React Email

Having explored multiple email template languages, we've found an optimal library for crafting email templates. This library allows us to build templates using React and seamlessly render them on the server in real-time, incorporating all the necessary data.

Link: https://react.email
Status: ✅
Keep Using

Email sending

Sendgrid

in the realm of sending emails, SendGrid has been our go-to solution for nearly every project. Its free plan is well-suited for MVP projects until they attract genuine paying users. SendGrid's user-friendly dashboard provides valuable insights into the statistics related to emails sent through the application.

Link: https://sendgrid.com
Status: ✅
Keep Using

Resend

Resend is a relatively new player on the market, developed by the same team behind React Email. We consider trying Resend instead of Sendgrid in our future internal projects.

Link: https://resend.com
Status: ▶️ Start Adoption

Backend

While our backend is powered by NodeJS, the intricacies of coding in pure NodeJS can be challenging. Hence, we leverage frameworks built on top of NodeJS for a more efficient development process.

NestJS

NestJS, an opinionated NodeJS framework, is exclusively built in TypeScript, offering excellent extensibility. This framework enables us to separate our backend into independent modules, significantly enhancing code maintainability. With comprehensive documentation and great learning materials, NestJS proves to be an excellent choice for onboarding new team members.

Link: https://nestjs.com
Status: ✅
Keep Using

ORM (Object Relational Mapper)

Prisma

Prisma stands out with its TypeScript support, although it comes with its own set of considerations. Designing the data model in Prisma involves a single file, which can be challenging to maintain in larger projects. Additionally, generating all types requires the ORM to modify the node_modules directory, posing potential issues in some cases.

Link: https://www.prisma.io
Status: ✅
Keep Using

Drizzle ORM

Drizzle ORM is a recently introduced TypeScript-based ORM boasting impressive features, ease of learning, and high-speed performance, as claimed by its authors. While we prefer testing new technologies in our internal small projects before adopting them for clients, Drizzle ORM is on our radar for future projects. Its promising features suggest it may address some of the issues we've encountered with Prisma.

Link: https://orm.drizzle.team
Status:
▶️ Start Adoption

Frontend

React

For the past 7 years, ReactJS has been our primary choice as the go-to frontend framework, and our commitment to it remains strong.

Its enduring stability, characterized by the absence of breaking changes throughout its history, coupled with support from various large companies, makes it a reliable base for our projects.

Link: https://react.dev
Status:
✅ Keep Using

React Server Components

The introduction of React Server Components marks one of the most significant changes in React's history, and we're closely monitoring its developments with excitement.

While it is supported by NextJS and other frameworks, the broader adoption across various frameworks and libraries is still underway for seamless integration with Server Components.

Link: https://vercel.com/blog/understanding-react-server-components
Status:
⏸️ Wait with Adoption

NextJS

NextJS has emerged as our preferred framework for the React stack, addressing a majority of the use-cases essential for our projects.

Backed by a successful company and a vibrant community, NextJS stays consistently updated and prudently manages breaking changes, further solidifying its position in our toolkit.

Link: https://nextjs.org
Status: ✅
Keep Using

UI Libraries

When prioritizing speed over design in the development of an MVP, it's practical to use pre-designed component libraries. Here's where libraries like Material UI, Bootstrap, Radix, and others truly shine.

Chakra UI

While Chakra UI stands out as a solid component library, it comes with its limitations. Not having an official Figma file poses a challenge in our workflows, where quick design visualization is crucial. Another notable drawback is Chakra UI's use of the css-in-js approach, potentially leading to performance issues, especially in large projects with Server-Side Rendering.

Link: https://chakra-ui.com
Status:
❌ Stop Using

RadixUI Primitives

In 2022, our friend Tair Asimov recommended Radix, and after experimenting with it, we officially started adopting it in all our new projects in 2023. The experience has been positive, and Radix has proven to work seamlessly.

Link: https://www.radix-ui.com/primitives
Status:
⏩ Keep Adoption

RadixUI Themes

Released in late 2023, RadixUI Themes quickly gained popularity within the RadixUI community. We're considering trying them out, potentially replacing Chakra UI, which we used in the past.

Links: https://www.radix-ui.com
Status:
▶️ Start Adoption

State Management

State management was the hardest topic in React for past years, but recently it changed in a very positive way. The mindset of the React developers has shifted towards separation of the Server and Client state, and libraries like React Query and SWR appeared.

React Query

One of the most revolutionary developments in the React ecosystem is React Query, fundamentally changing the way React code is written. It eliminates the need for boilerplate code, alleviates the complexities of state declarations seen in Redux, and removes concerns about when to refetch data from the server.

It's worth to mention that React Query has excellent documentation and a collection of tutorial videos created by the library maintainers.

Link: https://tanstack.com/query
Status:
✅ Keep Using

Zustand and Jotai

For storing application state outside of React, we turn to either Zustand or Jotai, depending on the specific case. Both libraries, authored by the same individual, offer simplicity, thorough documentation, and effective maintenance.

Link: https://zustand-demo.pmnd.rs and https://jotai.org
Status:
✅ Keep Using

Signals

Signals are increasingly being incorporated into various frameworks. In terms of developer experience, Signals offer notable advantages over hooks, making them a potential alternative to other state management libraries. Our friend, Ilya Zayats, recently shared a Signals implementation from the Preact Team. While we appreciate the direction this approach is taking, we're opting to wait until it gains more widespread usage before fully adopting it.

Link: https://preactjs.com/blog/introducing-signals/

Status: ⏸️ Wait with Adoption

Forms

Handling forms is perhaps the second most challenging aspect after State Management. Initially, we endeavored to enhance our developer experience (DX) by creating our own solutions, leveraging state managers. However, we eventually realized that there are libraries outperforming our bespoke solutions.

Formik

In previous projects, we used Formik, and it served us well. However, we encountered some limitations. The primary reason for discontinuing its use is that it was constrained to specific validation libraries, notably lacking support for Zod.

Don't get us wrong; it's a commendable library that fulfills its purpose, but we discovered another library that better suits our use cases.

Link: https://formik.org
Status:
❌ Stop Using

React-Hook-Form

We transitioned from Formik to React-Hook-Form, and it has proven to be an excellent choice for us! This library uses native form elements and meticulously tracks every aspect of the form's state.

Instead of directly registering form fields, we've developed wrappers for the fields, optimizing how we describe forms.

React Hook Form fields abstraction

Link: https://react-hook-form.com
Status:
✅ Keep Using

Validation

In the realm of validation libraries, they all more or less perform the same task admirably, with subtle differences. We don't strongly favor any particular validation library.

Yup

In our previous projects, we used Yup, but we encountered issues with TypeScript types. Consequently, we decided to explore alternative libraries to identify one better suited to our needs.

Link: https://github.com/jquense/yup
Status:
❌ Stop Using

Zod

Zod is constructed with TypeScript in mind, making it easier to interact with using TypeScript. Additionally, it has a more fluent schema definition and seamlessly integrates with localization.

Link: https://zod.dev
Status:
✅ Keep Using

Styling

Various approaches exist for styling modern web applications, such as pure CSS, preprocessors like Sass, css-in-js libraries like styled components, and style frameworks like Bulma and Tailwind. Despite experimenting with all these options, we have settled on using CSS with postprocessing through PostCSS.

CSS Modules

CSS Modules offer a cleaner way to write styles, eliminating the need for CSS nesting by confining the style scope to the component level. Each component can have its unique class names without requiring prefixes. This simplifies the stylesheets and significantly facilitates troubleshooting.

Link: https://github.com/css-modules/css-modules
Status:
✅ Keep Using

Testing

In our testing approach, we prioritize maintainability and a positive developer experience. As a result, we lean towards established technologies rather than extensive experimentation, ensuring a stable and efficient testing environment.

Jest

In our testing practices, we lean towards the traditional and proven approach, sticking with Jest, a tool that has stood the test of time.

Link: https://jestjs.io
Status:
✅ Keep Using

React Testing Library

While existing React testing methods leave us somewhat dissatisfied, the reality is that there aren't many viable alternatives at the moment. React Testing Library remains our default choice.

Link: https://testing-library.com
Status:
✅ Keep Using

Playwright

During the initial stages of MVP development, we usually forego end-to-end testing. However, as projects expand, it becomes prudent to cover key workflows with such tests. Playwright, a relatively recent addition, addresses the shortcomings of previous end-to-end testing tools. We plan to explore it further when the need for end-to-end testing arises.

Link: https://playwright.dev
Status:
▶️ Start Adoption

Did we forget anything?

Covering every aspect of application development is challenging, and we may have missed something. If there are specific parts of our tech stack you'd like to know more about, please let us know on Twitter and LinkedIn. We're more than happy to share our knowledge with the community!


Share this post