In this article, I want to emphasize some steps I follow when developing Node.js applications. These steps help me deliver reliable apps that cover business needs and are flexible and scalable for long-term growth.
Before starting with approaches and technologies that can solve problems, you should understand which issues you will solve. That’s why the essential thing you should be thinking about is the business context.
You can’t predict how the project will grow after production and what the business will need later. What you can do is discuss what the company needs for the MVP and develop the project in a scalable manner to prepare for later changes and migrations.
After you have concepts and goals for the MVP, let’s move down to the engineering level and examine approaches and technologies that can help ensure the application's scalability and reliability.
Framework
It’s better to start by choosing the architecture you will implement — monolith, serverless, or microservices. There’s the most common architectural approach for now, but you are not limited here.
You can choose a framework based on the architecture. Be careful here because many frameworks exist in the Node.js ecosystem.
My choices are:
Express.js is excellent for small projects or prototypes, which will be replaced later.
Nest.js covers several architectures, which is a default framework I consider when deciding what to use. It’s excellent for the monolith, which will be divided into domains and later transformed into separate microservices.
Moleculer will be good if you consider microservices. Still, I’m not a big fan of creating microservices when the project starts due to the complexity of the infrastructure and overall development processes. It’s an excellent framework for building microservices around your monolith or migrating from monolith to MS.
Next.js. Yes, I also consider it when deciding what I should use. It’s perfect if you are the only engineer who will work on the project or if all engineers are full-stack developers. Along with Vercel, you will have many benefits and be able to move quickly. However, later, you will probably need to migrate the backend to a separate codebase due to complexity.
Serverless is fantastic and probably the only solution for handling serverless architecture. It’s incredible for prototyping or small APIs. Still, I prefer to use it along with monolith or MS architectures as additional services or to handle narrow application parts where serverless is suitable.
Typescript
It’s suitable for almost every project and architecture. However, I don’t want to stop here because different articles have extensively described its benefits and drawbacks.
Data storage
Of course, you must choose SQL or NoSQL databases based on your business needs, or maybe you need both types of storage. I frequently select from several databases I worked on and have extensive experience with.
My default choice is PostgreSQL. It’s perfect relational storage with one of the best optimizers. It can cover most of your needs.
Frequently, I consider MongoDB, especially the serverless version. It’s a robust database that benefits from the relational model and is a powerful NoSQL database with many features that most storages don’t provide.
If you need a powerful NoSQL solution without relational benefits, consider DynamoDB. I also use it frequently, but mostly to handle narrow parts of projects. Be careful with this database because it has a special design you must learn before use. Don’t be like people who create many tables and try to use them as MongoDB or even as relational DB. In this case, you will have big problems when the product grows.
Also, I want to mention non-persistent storages like ElasticSearch and Redis, which I frequently use. ElasticSearch is not good when the project starts, but you can take it into account and use it later when you need to handle complex indexes and searches. Redis or another memory database is friendly and easy to implement. We frequently need a cache even at the beginning of the project, so it’s nice to have it.
Data access layer
Here, I use different approaches depending on the product side. I like starting with ORM and migrating to query builder or raw SQL in narrow parts. For NoSQL databases, I wouldn’t say I like ODM’s and prefer using drivers. For example, I don’t particularly appreciate using Mongoose and choose Node.js driver instead of this. I think it’s more flexible and simple than ODM, and it doesn’t require you to use the relational model.
For relational databases, there are many different libraries you can use here, but if you use an SQL database, you can consider TypeORM.
Development workflow
The last thing I want to mention is the development workflow. I like to keep it as simple as possible and use easy-to-implement tools to help automate workflows, moving to more flexible and complex solutions if needed. Here are my recommendations for tools you can consider:
Github actions. It’s an excellent CI/CD tool you can configure quickly and easily.
Dependabot is a fantastic tool for keeping packages in the latest versions and searching for vulnerabilities.
Terraform. I use it to manage infrastructure. It simplifies many things if at least a few people work on a project. As the project grows, it becomes massive, and maybe for better state management, you will need tools like Terragrunt to keep infrastructure-related code simple. If you use AWS as a cloud provider, you can also use AWS CDK. It’s a nice tool with Typescript support, but it’s available only for AWS, and if you need something from a different cloud infrastructure, the code will be much more complex than Terraform. That’s why I prefer the Terraform even for AWS.
Top comments (0)