DEV Community

Cover image for How we built a SaaS with React and AWS
Luca Restagno
Luca Restagno

Posted on

How we built a SaaS with React and AWS

I started iterspace with Marco Zani in the summer of 2018. The plan was to build a tool that would let people share clear feedback with the right context. A bit like Loom, but you get advanced commenting instruments and threads.

Visual feedback is not an entirely novel idea, of course, but the existing tools were all screenshot-based. So we set out to build a video-based product.

Architecture

iterspace Cloud Architecture

iterspace is a so-called single-page web app (SPA). Most of the logic is implemented in the client-side that runs in the browser and syncs updates to the backend view HTTP requests. The cloud notifies the app about updates made by other users via WebSocket.

All of the application's data are stored in a DynamoDB database in the Amazon Web Services (AWS) cloud. This gives us a lot of room to scale and keep the price contained.

All the services and data stores run in Amazon Web Services. We have AWS Amplify to host the client application on the public Internet and put it on edge through the CDN. The CDN routes the requests to either AWS S3 for static resources, such as images or videos.

JavaScript and Node.js

One of the most far-reaching tech decisions a startup needs to make is what programming language(s) to use.

For iterspace, we chose JavaScript and its server-side engine Node.js. Having one language across the whole stack is a significant speed boost, as it reduces the mental overhead of switching between parts of the stack.

The criticism that JavaScript gets is the lack of static typing. But by using the JavaScript superset TypeScript, we were able to add typings on both the front end and the back end.

Frontend

For iterspace, we picked React as the UI library of reference.

React is a small library focused on doing one thing — rendering UI. It does not dictate how to manage the state in a larger application. Therefore we picked Redux for the application state management and Redux Saga for the side effects handling.

We came from working experiences where we built a design system with a brand identity injected into it.

For a startup, speed is critical. Therefore we evaluated several component libraries. The prerequisites were React, styled-component, and components written with the functional approach. We picked Zendesk Garden from Zendesk as the base React components library, and I must say that the decision was worth it.

For startups, development speed is critical. So we started using Storybook to build the components in isolation. Basically, when you need to create a new component, you make a story first. A story is a page that renders one or more components.
As you write the code in the new component file, you see it updated almost immediately in the browser.

It helps you a lot in thinking about Presentational and Container Components.

Backend

The backend service for iterspace is a lightweight layer between the client and the data store. It is a GraphQL API feed by Lambda Functions (Serverless).

There is no CPU-intensive processing. Therefore, there was no need for always running servers.

We used Lerna to manage a monorepo containing all the Lambda Functions code in different packages. In addition, we created common packages to share the core model between the other Lambda Functions.

Video

iterspace stores and serves screen recordings, and therefore we had to understand how to distribute video reliably.
Most of the recordings come from the browser (WebM with the H264 video codec), but a video can be uploaded too, and therefore we had to support multiple formats (Mov, Mp4).

We use AWS Elemental MediaConvert to encode the video to WebM and Mp4. We had to encode both formats because the WebM playback works on most browsers (Chrome, Edge, Firefox) but not in Safari.

Conclusions

Building a product is a highly challenging activity. It requires many decisions to be taken rapidly. Nevertheless, we try to deliver value to the customers as soon as possible, even with rough features.
Then we gather feedback, adjust the feature based on that, and iterate the process.
Moreover, we use iterspace while working on iterspace! And we are the first customers of our own product.

I hope you enjoyed 🙌

If you are interested in building a SaaS and web development, you might consider subscribing to my newsletter

Top comments (15)

Collapse
 
thealexkates profile image
Alex Kates

We are huge fans of Amplify at creditgenie.com as well.

Great article! Glad to see other people using this tech in a similar way as us.

Feel free to check out my write up as well! dev.to/aws-builders/how-we-scaled-...

Collapse
 
ikoichi profile image
Luca Restagno

Thanks for sharing Alex!

You'll look into the article 😉

Collapse
 
berlangerc profile image
berlangerc

Hello, thank you for describing the architecture!
Was there any reason not to use S3 for "hosting" your SPA instead of amplify?
Price wise? Other things?

Collapse
 
ikoichi profile image
Luca Restagno • Edited

Hi berlangerc!

With Amplify you can connect your git repo and configure deployment pipelines, you get simplified custom domain configuration, multiple environments, rewrites and redirects, custom headers support, monitoring and notifications and so on.

You can definitely go with S3 but Amplify provides a complete hosting solution (at a price of ~6$/month)

Collapse
 
berlangerc profile image
berlangerc

I see! Ok thanks! 😄

Collapse
 
pschoeps profile image
Patrick Schoeps

This is sweet! Thank you. Maybe this is a dumb question but if Node is your backend and you went serverless, where exactly does it fit into your stack? Do your serverless functions run in a Node runtime?

Collapse
 
ikoichi profile image
Luca Restagno

Hi Patrick!

The way Lambda Functions works is that you select the runtime (Node.js in my case) and you upload the code to execute.

Then you link the Lambda to other services, like API Gateway for instance.
So that when a specific URL is called, your Lambda Function is invoked.

You can plug them into many services, like DB or storage triggers, or AWS AppSync for GraphQL APIs.

The code execution environment and the handling of the runtime are delegated to AWS.

Does it reply to your question?

Collapse
 
pschoeps profile image
Patrick Schoeps

Yeah that makes sense, thanks for answering my question!

Collapse
 
pflash profile image
Precious adeyinka

I love the presentation style writing and every details included, the breakdown of the system architecture/design and the reasons backing them up is very narrative and descriptive, congratulations and looking forward to more achievements for you guys, cheers!

Collapse
 
ikoichi profile image
Luca Restagno

Thanks! I really appreciate your kind words 🙌

I tried to be more descriptive as possible without losing details.

Collapse
 
octaviannn profile image
Octavian • Edited

Curious why Rails was not picked? Was it because you were not familiar with Ruby? Also can you elaborate on the costs involved by this choice of architecture? Did you have any funding?

Collapse
 
ikoichi profile image
Luca Restagno

Just for that yes 😉 I'm much more familiar with the JS ecosystem.

Would you suggest Ruby on Rails? And why?

Collapse
 
octaviannn profile image
Octavian • Edited

Same reason - I am familiar with Ruby and Rails and it's all one codebase. Way simpler than the architecture you are using but arguably not as cool as yours.

Collapse
 
miss_vitriola profile image
Nancy C

Thanks for the great article. Do you have one frontend for this application? What is your opinion on micro frontends?

Collapse
 
ikoichi profile image
Luca Restagno

Hi Nancy!

For this application I have one single frontend app (even the chrome extension code is inside the same project, so I can reuse the React components of the web app).

I like micro frontends, but they add an overhead — you need to manage all of them separately, cross dependencies, the release of each of them.

So, in my opinion, it's good to start with a monolithic app, and if it increases in compexity, at a certain point, switch to a micro frontend architecture.

There are benefits in using a micro frontend architecture like:

  • smaller projects
  • quicker continuous integration pipelines
  • reduced code complexity

I hope it helps! 🙌