As someone who loves cutting-edge technology, I choose to build my first SaaS with a modern tech stack. With the rise of JAMStack and serverless architecture, I created PostMage with Next JS static generation for the frontend and the Node.js backend deployed to AWS.
Because I'm a solo full-stack developer, my time and resources are extremely limited. In this article, I'll share all the technologies I use to build my SaaS product: from programming language to development tools. You'll find how I overcome this challenge to build a SaaS as a solo developer.
Hope my story gives you the inspiration to create your SaaS products.
For building my SaaS, I wrote every line of code in TypeScript. Yes, all the code: Frontend, Backend and also, Infrastructure as code in TypeScript.
The whole project only uses one and unique programming language. No time to learn new languages and save time by making the code easy to maintain.
Why did I choose TypeScript? It makes the development much more pleasant with strongly-typed and has better integration to IDE. So, if you are still a JavaScript developer, you should give it a try.
For the frontend, I use Next.js. It's a React framework to build a complex application. The good news, Next JS supports TypeScript out-of-the-box.
I use Tailwind CSS styling the React components. As a developer, you usually build an ugly interface. With Tailwind CSS, you can have now build a not so ugly interface even if you aren't a designer.
As a true believer of JAMStack, I have previously taken some time to try Jekyll, Hexo and 11ty for different projects. I choose to build my SaaS in static generated mode using Next JS. So, at build time, all the pages are generated and pre-rendered. Perfect for SEO, cheap hosting, fast, secure, and highly scalable.
I use Cloudflare Pages as a hosting service for the frontend, it's a brand new alternative to Netlify or Vercel. Cloudflare has announced it in December 2020 in beta and released it to the public in April 2021.
There is some small missing feature (nothing big) in Pages. Until the Cloudflare team solve it, I've found temporary workarounds. So, it isn't a big deal.
The good thing about Cloudflare Page is its generous free tier: unlimited bandwidth (Vercel and Netlify are limited to 100GB per month) and you can set up a password-protected website for free (not included for free in Vercel or Netlify).
On the backend side, I've built a REST API with Express.js and Serverless Framework. To support TypeScript in Serverless Framework, I use a serverless-bundle plugin. Express.js needs another plugin to work with Serverless Framework named serverless-http.
For better developer experience, I've also used two other plugins: serverless-dotenv-plugin and serverless-offline. The first plugin is to support dotenv files and the second one is to run Serverless Framework on your local computer.
As a solo developer, I choose serverless architecture for making my life easier with easy deployment, low maintenance, and scalable backend. No need to become a DevOps engineer: no need to SSH, make OS updates, configure proxy/webserver/load balancer/firewall, etc.
The REST API is protected by the IAM authentication. It's AWS built-in feature to secure any AWS resources, in our case, API gateway and AWS lambda. It denies the API invocation when the user isn't connected to the SaaS application. So, when it's protected, external actors won't be able to invoke your resource.
Because the API is deployed to AWS, I choose to use AWS Cognito for authentication. The good thing is that Cognito saves a lot of time by providing everything you need to implement authentication for your SaaS. You get access without any effort to Email authentication and Social sign-in (Facebook, Google, Apple and Amazon).
The connection between AWS Cognito and React frontend is done through AWS Amplify. Amplify provides React components and code for making your frontend integration to AWS easier and faster.
Major and well-known databases like PostgreSQL and MySQL don't fit very well in Serverless architecture. Due to the nature of serverless, it can create a lot of connections to the database and exhaust the database connection limit.
On most providers, even if you don't have any traffic on your SaaS, you still need to pay your DB instance. On the opposite, when your application starts to grow, your database can quickly become the bottleneck.
As a solo full-stack developer, I wanted something extremely easy to manage and 100% compatible with serverless. So, I choose DynamoDB as a primary database.
DynamoDB is a NoSQL database fully managed by AWS and I use it to store user states. They almost handle everything and I just need to focus on my code.
As you can see, I use several AWS services for my SaaS app. It's extremely painful to set up manually cloud resources in each environment (development, staging or production) and hard to maintain consistency between them.
AWS gives developers access to AWS CDK where you can define your cloud resources in TypeScript. In one command, you can deploy to your AWS account and get everything provisioned.
Like many developers, I use Git and GitHub for the version control of my code. Many modern hosting services like Vercel and Netlify, Cloudflare pages automatically build and deploy your code at each commit. If you work with Git branches, you can also preview the results without pushing them to production.
For the backend and the infrastructure, I use a third-party service named Seed.run to deploy automatically at each commit. Like the frontend, it also builds and deploys the backend resources on AWS.
As you can doubt, I use Cloudflare for DNS and CDN without any surprise ;) Cloudflare Pages automatically deploy your code in the Cloudflare network, I only need to point my domain to Cloudflare DNS server and they handle the rest. Using Cloudflare, you get plenty of security features like a firewall and a DDoS protection for your SaaS products.
I use Sentry as the error tracking solution. It automatically reports when something goes wrong with useful information like stack trace, breadcrumbs (a trail of events that happened before an issue), browser information, OS information, etc. It makes debugging in production much easier with enriched data:
Sentry is only set up for the frontend and not for the REST API, I keep using the native solution. Indeed, Sentry with AWS lambda creates a lot of overhead and the setup wasn't straightforward. In the next section, you'll find the solution I use for error tracking in the backend.
AWS Lambda automatically sends logs to AWS CloudWatch, so no need to use Sentry. Here is an example of logs stored in CloudWatch:
You also get access to your lambda metrics. Perfect to understand how your serverless functions behave and detect if there are any errors.
I also use Lumigo to have additional information for my logging and monitoring. The interface is easier to use compared to Cloudwatch:
You can also enable tracing in Lumigo where you can visualize your AWS service and external API calls. It makes your debugging session easier by letting you know if there is an error in your code or it's from an external service.
The last piece of a SaaS and the most important thing for a business is to accept payment. Accepting a one-time payment is hard but, the task for recurrent payment is much complex. Unfortunately, for a SaaS business, we need to handle the second case.
Your customers need to choose the plan and enter their personal information when they subscribe for the first time.
After that, your users should have a self-service portal where they can manage their plan: upgrade, downgrade, cancel, pause, resume their subscription plan.
They sometimes also need to update their personal information. And, they also need access to their invoice history when needed.
Stripe can manage everything I mention in this section, it hides all these complexities and makes the integration to payment easier.
It took me 5 months of development to build this full-stack React SaaS template. Instead of focusing on my business, I was solving these technical details. Building the first version of your SaaS should only take 1 month and not 5.
By going through this long journey, I've learned so many things and I've made tons of mistakes. I hope others developers won't do the same mistakes, so I build Nextless JS, React Boilerplate for SaaS products.
With Nextless.js, you get everything I mentioned in this article without you writing any line of code. Save you time, focus on things that matter and launch your SaaS faster.