How to choose the right stack for you next project

Saas starter package has been rising in popularity recently, it helps developers make their startup quicker, ship product faster than ever before. One of the most successful starter packages I can name is ShipFast.

The downside is when you use someone’s code, it’s harder to customize it the way you want. And when you want to customize the prebuilt component, it requires learning curve. If you use the open source starter package, sometimes there will be licensing concerns about what you can do and what’s not.

With the rise of all available libraries, frameworks and especially AI, it’s not hard to build your own starter stack.

In this post, I will show you my way to develop a stack for my next project, which frontend, backend stack I choose, which auth method I use, and a little bit about DDoS awareness

The complete source code in this post is available here

Requirement

So my stack must ensure some of the requirements:

  • Must be easy to deploy - startup environment must run fast

  • Can be hosted for free - we have no money at the start

  • Can scale later on

  • DDoS awareness - to prevent a skyrocket cloud bills while you’re sleep

  • SEO friendly.

From all the requirements above, you can say that Next.js is a great fit. It’s an all-in-one tool: static site generation, frontend, API server, serverless hosting on Vercel with big free tier,.. Because it’s an all-in-one tool so it's complicated to start, customizing is hard when you have little to no experience with this framework.

And I want to separate the frontend and backend to make it clearer and easier.

So for Frontend I choose Astro + React + Shadcn

The great thing about Astro is it makes clear distinction about which part is static site rendering for SEO purposes, which part is rendered by React, like this

pages/app/[…all].astro

---
import { App } from "../react/App";
export const prerender = false;
---

<App client:only="react" />

And that means every subdirectory domain.name/app/ will now be rendered all by React

Astro is supported to deploy on many major cloud platforms, I like Cloudflare pages since it’s completely free.

For Backend I choose Fastify

It’s one of the most popular nodejs backend frameworks, and the greatest thing is Fastify could be deployed to some serverless cloud platforms: Vercel, Aws lambda, Google Cloud Functions,.. but why serverless? Most platforms have generous free tiers my friend.

To avoid DDoS skyrocket bill, we shouldn’t deploy our serverless server to a pay-as-go subscription, that’s means the only option for me is to deploy Fastify server to Vercel, or Netlify.

The setup with Vercel is straightforward

api/index.js

import mongoose from "mongoose";

const app = Fastify({
  logger: true,
});

app.get("/", async (req, reply) => {
  return reply.send("Hello World");
});

export default async function handler(req, reply) {
  await app.ready();
  await mongoose.connect(process.env.MONGO_URI);
  app.server.emit("request", req, reply);
}

And vercel.json file

{
  "rewrites": [
    {
      "source": "/(.*)",
      "destination": "/api"
    }
  ],
  "framework": null
}

Serverless environment has some limitations, but you can always switch Fastify to run on a full VM server when you want an environment without cold start time, scaling with VMs, or you just have a specific need about the runtime.

Understanding DDoS Risks

A DDoS attack occurs when multiple systems flood the bandwidth or resources of a targeted system, usually one or more web servers. This can overwhelm your application, causing it to slow down and crash.

For serverless deployments, this can translate to a sudden spike in resource usage and, consequently, costs.

Strategies to prevent it

  1. Avoid Pay-as-You-Go for Serverless

    So when we want to deploy Fastify as a serverless server, avoid using pay as you go subscription will be the easiest way to avoid DDoS risks.

  2. Utilize Cloudflare Protection
    The next thing you could do is setup your server behind Cloudflare proxy, and enable Cloudflare’s DDoS protection. This setup will prevent most of the DDoS attack.

  3. Implement Rate Limiting
    Limit number of request from single source is great way to prevent DDoS. You could easy implement rate limiting using Fastify middleware

   const fastify = require('fastify')()
   fastify.register(require('@fastify/rate-limit'), {
     max: 100,
     timeWindow: '1 minute'
   })

Authentication

Another important thing to consider is choosing an authentication method for our stack, we could either use third-party library or an authentication service.

Using third-party library will give us more control with the lowest cost, but maintaining, scaling, and compliance stuff will be a problem. On the other side using an authentication service help us save a lot of time, always updated but it could increase the cost when our app grows. Choosing the right option is just hard

Currently, I’m using an authentication service, I will try using third party library on another post.

I used Clerk before, they have pretty good generous free tier, easy to implement. They have first-class support for React and an available middleware for Fastify too, which is so good.

Note: This post isn’t sponsored by Vercel or Clerk - I have so little audience for that stuff @@

Example implement Clerk in React and Fastify

  return (
    <React.StrictMode>
      <ClerkProvider publishableKey={CLERK_PUBLISHABLE_KEY} afterSignOutUrl="/">
        <SignedOut>
          <SignInButton />
        </SignedOut>
        <SignedIn>
          <a href="/dashboard">Dashboard</a>
          <a href="/dashboard/settings">Settings</a>
          <a href="/dashboard/profile">Profile</a>
          <UserButton />
        </SignedIn>
        <App />
      </ClerkProvider>
    </React.StrictMode>
  );
import Fastify from "fastify";
import { clerkClient, clerkPlugin, getAuth } from "@clerk/fastify";
import cors from "@fastify/cors";

const app = Fastify({
  logger: true,
});
app.register(clerkPlugin);

app.get("/user", async (req, reply) => {
  const { userId } = getAuth(req);
  if (!userId) {
    return reply.code(401).send();
  }
  return reply.send({ userId });
});

The complete source code in this post available here

Recap

With many all available libraries and cloud platforms, build your own Saas starter is so easy and fast. My personal way might not fit your case, but I hope how I approach it helps.

Thank you for reading, have a nice day.

0
Subscribe to my newsletter

Read articles from Định Nguyễn Trương directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Định Nguyễn Trương
Định Nguyễn Trương