A technology stack is a full set of technologies that companies use to build a digital product or run a project. In it, you have everything ranging from programming languages, frameworks, databases, frontend and backend tools to services accessed via an API. Code & Pepper also has its technology stack. With it, you can quickly build your minimum viable product (MVP) or a full-blown application. How exactly and what comes with our tech stack?

Table of contents

Different tech stacks for different needs

A technology stack can be broken down into different tools for frontend, backend, and infrastructure. Each one needs a specific approach and toolset to best utilize the company’s approach to creating digital products and also the client’s needs. What is important on each frontline?

Technology stack is not only shaped by specific requirements or goals. You have to take into account the popularity and maturity of selected technologies or solutions. You don’t want to choose technologies for which it will be hard to find engineers keen to use them. You also want to avoid solutions without a vibrant community of supporters and developers. 

Our technology stack is (deceptively) short yet very effective

We use the following technologies:

Frontend

  • React for web development
  • React Native for mobile development
  • TypeScript/JavaScript

Backend

  • Node.js for classic applications
  • Amazon Web Services (AWS) for serverless architecture
  • TypeScript/JavaScript

Infrastructure

  • Amazon Web Services 
  • AWS Cloud Development Kit (CDK)
  • GraphQL

This is the basic toolset which we will expand later on in the text. For now, let’s just say it covers all the needs of modern digital products. With it, you can build applications quickly and modify them according to the market’s demands.

You may wonder why our tech stack is restricted to few technologies. As you will see later on, it’s not short at all. We complement and support it with frameworks, databases and other necessary components. All in the name of creating reliable digital products. For further details, please scroll to the section “Our tech stack meaning for your business”. For now, let’s just say that our approach to creating a tech stack is characterized by nothing too special. It’s just a conscious decision about technologies that we consider the most effective. Including cloud, which we will tackle in a second. 

We go deep into our set of technologies. By doing projects mainly in them, we understand tools better than many other companies out there. We can develop quicker, implement additional security measures and fix bugs with extra attention to detail. That’s an undisputed advantage over companies that create anything through everything

Start a tech stack with a cloud in mind

The number of companies keeping a server infrastructure to support products melts with each passing year. Cloud computing proved itself to be a much more affordable solution. It offers stability, flexibility and advanced security measures. Serverless approach (which eliminates costly and complicated infrastructure from the equation) is often seen on a market. Serverless eliminates the necessity of managing the infrastructure, grants agility and costs are present only if you actually use something.

Our belief at Code & Pepper is that it’s easier to build a performing technology stack when you start with a cloud and go from there. That way you will have even more control over the process of picking and choosing. You will have the best-suited elements of the puzzle as well. 

Through our technology stack, we create cloud-native applications, which by nature:

  • allow faster market release (true for a minimum viable product – MVP and full products as well)
  • allow more efficient disaster recovery
  • guarantee high reliability and availability
  • are more cost-efficient
  • are highly scalable
  • deliver easier management options
  • avoid vendor lock-in (if you use Kubernetes, Docker or containers)
  • are based on microservices which provide many major benefits from the get-go
  • are event-driven (which means faster development reaction to any potential challenges)

We do develop products with serverless in mind but it’s not always the case. Some products rely on raw computing power and need time to process tasks. In this case, going for the cloud (infrastructure as a service, IaaS) would be counter-intuitive. We always think about the cloud but fit the tech to serve a product, not the other way around

The other important assumption is working with infrastructure as a code (IaC) in mind. With it, you can easily manage files and keep track of the infrastructure changes. You also have advanced options for deployment, like centralized and one-command control, minimized downtime, the ability to embrace concurrent deployments, etc. 

Infrastructure as a code gives us enhanced control over what is set up in a cloud and eliminates manual processes that are prone to human error. We can often benefit from blue-green deployments which, with just a click away, turns a release application model into a production model. With user traffic, data and version of the app intact and identical. Magic, that doesn’t require a wand, cat, or a hat. We don’t have to manually set up and control everything, which translates into a cost-effective process for you as our client. Less time spent on mundane actions, more time in a sprint for real development, higher cost-effective rate. 

Infrastructure as a code isn’t a part of the technology stack per se. It lands in a different category. When it comes to software development, we have:

  • technology stack
  • characteristic of an architecture 
  • best practices of development (plus individual company approach)

IaC is a part of the last one. All three categories are inseparable parts of the same thing, which is product development. The important part is that they are, while connected, different things.

Amazing Web Services

We have chosen Amazon Web Services (AWS). With its amazing market share reaching around 40% and vast toolset available for use, we are comfortable with the decision. AWS gives us a powerful range of bigger and smaller applications that, while running in the background or being used per use case, secure the application and its performance. Since AWS has the longest track record, its offer is the most complete and best suits our needs. A good argument for its usability is one number – 15+. That’s how many AWS has specialized databases. For nearly every need, suitable for many, widely different projects. 

There is, for example, the Quantum Ledger Database which has a very rich history mode. You can browse through version history and track data versions for every single entry, which is very useful in keeping tabs on who changed what and when. The number of innovations available in AWS is unmatched on the market. 

It’s a matter of national security

If the company is a country, your users are your nation. The security of the app itself and its data should have a priority for a software development company. Since we went with the serverless approach, ensuring the application’s security is easier.

For example, nobody will get access to AWS Lambda (more on that below) or its underlying operating system because it’s tightly guarded by Amazon Web Services. 

If you want to know more, stay tuned. Soon we will publish a separate and very detailed article on security in AWS. What is guaranteed by Amazon, what is on our side? A lot of practical knowledge!

An interesting and important topic that spawns out of security, is reliability. Under the cloud, especially in AWS, it’s a lot easier to go through the disaster recovery process. There are multiple regions for data management but you need to use at least two of them to have multi site active/active disaster recovery. If something happens, we can reconstruct the database because there is constant data replication between two regions. This is possible through a DNS (Amazon Route 53) and takes only a second. Naturally, it can also be done automatically, via health checks.

Our tech stack meaning for your business

For the communication between frontend and backend, we use GraphQL. One of the reasons behind choosing this technology was flexibility. A client can always pick and choose what he wants to squeeze off the backend, and GraphQL delivers in spades. Streaming data is highly optimized, which is great for business. Let’s say you want to pull only the names of all app’s users. With GraphQL it’s possible – you won’t get their entire bios, with surnames, lists of friends, social security numbers, etc. The data is filtered, sorted and ready for further action. 

The other argument comes in the form of built-in features like strong typification and an out-of-the-box scheme with which you can define an API. You no longer need additional tools like OpenAPI. GraphQL also defines operations like queries, mutations and subscriptions – real-time communication between frontend and backend, initialized by a backend. When something happens there (like a new post on a blog), it will automatically appear on the frontend side of things. Sure, you can achieve the same result with, for example, WebSockets but with GraphQL data and communication are more structured. 

Libraries and frameworks

We like to use Amazon Amplify which allows communicating with different services like Cognito or S3. We also utilize the Apollo Client which is a library used for frontend, to communicate with GraphQL. It makes inquiries easier – we send them to AWS AppSync in which we directly work with databases (DynamoDB for example) or utilize a relational database (in AWS it’s called Aurora).

Another useful tool is Elasticsearch which is great for searching automatically. When you have a large database, you can’t afford to do everything manually. 

For business logic and databases that are not directly supported by App Sync, we use AWS Lambda

For user authorization and identification, we use Amazon Cognito

For content delivery, our teams use Amazon CloudFront. Because it’s easier to download content from your local server, rather than a distant location, half across the globe. 

To work with containers and build scalable web applications, we use NestJS

For the library of net components, we use MUI. (previously Material UI). This is an implementation of Google’s Material Design, crafted especially for React. This is a complete and feature-full library that fully supports TypeScript. Another advantage of Material UI comes from components for Sketch and Figma, which benefit our user experience and user interface designers. 

We have chosen AWS Amplify to support the frontend with GraphQL inquiries. It’s the most mature and feature-heavy tool that provides scalability and options. It speeds up the deployment of any web application. We can even set up an environment to test only the fresh code added by a given developer. The setup vanishes after the merge with the master branch, leaving no artifacts behind but giving us additional options on the way to the merge.

Analytics

The matter of analytics and business intelligence is also very important. To know what’s going on in your app and how you can leverage data, we use Amazon Pinpoint for reporting events. For storage, we use Amazon S3 (Simple Storage Service). With it, we can throw data into the mix and what comes out is an interesting mix of lists, graphs, etc. We also use Amazon QuickSight, Amazon Redshift

With all these tools we can run complete analytics throughout the whole application. We can pull currently needed information as well as do a complete diagnostic.

Another interesting software we use is called Amazon EventBridge. It’s designed to spot and filter events based on their importance and occurrences.

We also use CloudWatch for monitoring events in applications (for example what happens in Lambdas). Cloud Watch is also good for checking database response time. 

Microservices

Since we use cloud computing for our operations and product building, we have adopted microservices. They have many advantages but to utilize them all, we have adopted polyglot persistence – it’s a best practice for building microservices. Each microservice should have its own data store. That way you won’t have a close relationship between them on a database level. A positive side effect is that we can choose the best database for the job – either a NoSQL or relational database. And that’s for every microservice or even a use case. 

Quality assurance

Since we are an agile company, we have decided on a specific approach to tools. We prefer tools over rules adopted by testers. We don’t want to stick to the same toolset every single time, since some of them don’t meet the requirements needed for a given project. This approach gives us the flexibility to choose the best software out there while staying true to the client’s needs. 

We write unit tests and integration tests. Usually, we assume that we want to have at least 70% coverage for the code. Our runtime for the test is called Jest. It can not only launch tests but also mock features which are very useful; this trick saves developers some time.

For our web end-to-end tests, we use Cypress and Playwright. The second tool is developed by Microsoft. It’s not fully matured but its features are very interesting and complement Cypress in a good way. We decided to give it a go in a few projects and since then, the company has stuck with both for better occurrences coverage, yet we don’t use them at the same time. With it, we can also test additional things like service workers for progressive web apps. 

For mobile testing, we have a framework called Detox. It can be easily integrated with any React Native app. Additional benefit – it’s almost effortless. We have compared Detox with other tools like Appium and decided to stick with it. It makes our work simpler by relieving the team from heavy lifting. We can write tests quicker and easier; that is what the testing process should look like.  

Tech in our technology stack

We decided on TypeScript because of its popularity. Popularity means fewer bugs, more tools, better support in frameworks. That translates into stability and predictability for your project. Probably the most important argument though, is that we can use TypeScript in all aspects of our technology stack. We can utilize it on the frontend, backend (through Node.js) and use it in defining our approach to infrastructure (infrastructure as a code). 

By using TypeScript as the main language for everything, we as software developers, have natural benefits. The code is clear and highly readable, developers are prone to adopt a full-stack approach for their professional career choice. This makes development smoother because some engineers like to work on the frontend and backend; with the same language for both, it’s just simpler. 

Another argument for TypeScript is AWS’s native support for the language and something called the “Cloud Development Kit” (CDK – it’s a library that grants access to widgets necessary to write user interfaces). This, as a result, is very important to us because it gives an additional level of safety net and strengthens arguments for the future nature of the tool itself.

And speaking about support… TypeScript was developed by Microsoft but enhanced by Google. The collaboration of these two giants shows that TypeScript won’t go anywhere, at least in the foreseeable future. It will be supported, it will be expanded. That means if something changes, we as a software development company, have a few years to react and choose an alternative language. For the time being though, Typescript is thriving (more on that in a bit). It’s backed by giants and it’s open-source, which gives a compelling advantage over alternatives.

After we have decided on TypeScript, we immediately went for Node.js. It’s a natural choice for writing for the backend. This is a running environment for JavaScript and TypeScript. With a large variety of frameworks (like NestJS), libraries and vibrant community, it’s the only choice available on the market but also the choice. Backed with solid arguments, not with the lack of an alternative. 

For Infrastructure as Code, we have adopted AWS CDK (that’s compiling to Cloud Formation). It gives us an easy way to create a collection of AWS-related and third-party-related resources, needed for a serverless approach. We can spend less time managing resources and keeping them updated. That means more time for what your project really needs: code. With Cloud Formation providing options like automatic rollback, we can perform even more efficiently. 

Our approach to API supports a serverless mindset. With a previously mentioned GraphQL, we have already touched the subject a little. With our approach, we can scale and change microservices according to needs and current vision for the project but the API itself stays the same. This means that we can even start a project in a monolith architecture and then transform it to support microservices. A huge advantage down the road for everyone involved. 

We chose React for its popularity. Choosing the right technology is not a miss congeniality contest but if you look for the entire ecosystem (libraries, additional tools, etc.) then React seems to be a natural choice. It also has very good support for TypeScript. We also can use our skills in creating mobile applications under React Native. We can also reuse parts of the code, which is beneficial for time and the project’s budget. It’s true for many areas but especially for communications with API and business logic. 

An argument for React Native – one codebase for iOS and Android. This significantly simplifies the work and shortens time, which is invaluable in any project. Plus, you don’t have to pay for additional development. Aside from that, the technology is so intuitive that we can use our web development skills in React and even reuse parts of the code for business logic, services communicating with API, etc. We can also view changes with a “live reloading” feature. This real-time feedback gives information about any changes to the code and their impact on what has been done to date. 

Continuous integration/continuous development (CI/CD). We wanted to have a seamless pipeline. That’s why we share resources between Amplify and GitHub Actions. Under them, we fire up tools like Prettier for code formatting. We also use ESLint for static code analysis. We also run integration and end-to-end tests (simulating ways the user interacts with the product.) That’s not all – we use SonarCloud and Lighthouse as well as run tests.

In general, there is a lot to do before we run with the deployment. As Code & Pepper, we want to make sure our code is valid, application stable and integration seamless. That everything works as intended and bugs are minor, and easily fixable. We always check for new versions of tools, frameworks and libraries to make sure everything is up to date and doesn’t have a negative impact on the app, especially for security and optimization. 

We also use Google’s Lighthouse. It’s a tool that can scan a web application for potential problems with SEO, security and performance.

Another interesting tool is Bitrise, which we use as our CI/CD pipeline for mobile applications. 

Our way AND the highway

Although we listed a bunch of tech we work with on a daily basis, we are opened to different languages and tools as well. If there’s a need of creating a high-performing microservice, we would go with Go or Rust. If there’s something to do in the machine learning area, we would stick with Python. It’s all a matter of the task at hand and the nature of the product itself.

For most projects, we recommend TypeScript. It’s elastic, highly reliable and has momentum among developers, which only proves our point. According to multiple reports by GitHub, TypeScript’s popularity is on the rise. Ruby, on the other hand, popular a decade ago, now experiences a dramatic decrease in interest. An interesting survey taken by Stack Overflow shows how different languages are now dealing with the market. TypeScript is among the most valued ones. 

If you bet on the wrong horse, the development process will be longer, more difficult from a technical point of view and more expensive. If you do this right, you increase the chance for creating a performing product. This footnote is important not only for us but for clients as well. We always try to talk and persuade you. Explain what impact different languages, tools, and frameworks have on what you want to achieve.

Tech stack comes from what you need

Sometimes needs and the current popularity of tools coexist, as we mentioned here or there in this article. For the most part, it’s all about your business needs and approach to making software. Do you want it to be future-proof? Easy to enhance and maintain? 

Is there the best technology for FinTech or any other area of software development for that matter? How to select technology in FinTech? These are not easy questions and the answer is even more complicated. No, there is no perfect technology that fits all. Software development is not about the perfect fit that suits all projects, it should not be about compromises either. It should be about thinking what is the best on the market and what can benefit you as the customer.

This calls for another fit – between you and the software development company. You can choose Code & Pepper – the team that cherry-picks only the best, not necessarily low-hanging fruits.