Skip to content
All insights

engineering//3 min read

A boring stack for a new SaaS, and why boring wins

The best stack for a new product is the one your team can ship and debug at 2 a.m. A practical default for web SaaS, what each piece is for, and when to reconsider.

Digitat engineeringProduct studio, Mumbai
Minimalist engineering desk with clean code on monitor representing pragmatic technology stacks

In short

  • Choose technology your team already knows well; novelty spends your attention on the wrong problems.
  • Start with a modular monolith and one Postgres database. Split only when a real constraint forces it.
  • TypeScript end to end removes a whole class of integration bugs between front end and back end.
  • Write down when you would reconsider each choice, so the decision stays honest.

Every early product has a budget of novelty. Spend it on the thing your customers pay for, not on your infrastructure. That is the whole argument for a boring stack: well-documented, widely used tools that fail in known ways and that you can hire for.

A sensible default

This is the shape we reach for when a web SaaS has no constraint pulling it elsewhere. None of it is exotic, which is the point.

Layer

Default

Why

Reconsider when

Language

TypeScript

One language and one type system across client and server

Heavy data science or ML work dominates

Web framework

Next.js (App Router)

Server rendering, routing and APIs in one place

The product is mostly an API with a thin client

Database

PostgreSQL

Relational integrity, JSON when needed, full-text search, mature tooling

You genuinely need a different data model at scale

Data access

Drizzle or Prisma

Typed queries and migrations in the repo

Queries get complex enough to want raw SQL everywhere

Auth

A managed provider or a proven library

Security is not your differentiator

You need enterprise SSO beyond what the tool offers

Payments

Stripe or a regional equivalent

Billing edge cases are endless

Never, until billing itself is your product

Hosting

A managed platform

Deploys, previews and TLS without an ops team

Costs or compliance push you to your own cloud account

Monolith first, with seams

One deployable application and one database is the fastest way to ship and the easiest to debug. The trick is to keep seams inside it: modules organised by domain (billing, accounts, the core feature), each with its own data access and a narrow public interface. If you ever need to pull one out into a service, the seam is already there.

txt
src/
  modules/
    accounts/   # sign-up, teams, roles
    billing/    # plans, subscriptions, invoices
    reports/    # the core product
  app/          # routes call module services, never the database directly

Design the data model early

Frameworks are easy to change; data is not. Spend real time on the schema: name things clearly, use foreign keys, and decide early how tenants are separated. A typed schema in the repo keeps the database and the code honest with each other.

ts
import { pgTable, serial, text, integer, timestamp } from "drizzle-orm/pg-core";

export const teams = pgTable("teams", {
  id: serial("id").primaryKey(),
  name: text("name").notNull(),
  createdAt: timestamp("created_at").defaultNow().notNull(),
});

export const projects = pgTable("projects", {
  id: serial("id").primaryKey(),
  teamId: integer("team_id").references(() => teams.id).notNull(),
  name: text("name").notNull(),
});

Things a boring stack still needs

  • Error tracking wired in on the first day, front end and back end.
  • Background jobs for anything slow: emails, imports, AI calls. A Postgres-backed queue is enough for a long time.
  • Feature flags, even simple ones in the database, so you can ship dark and turn things on per customer.
  • Backups you have restored at least once. An untested backup is a hope, not a backup.
Choose the stack you can debug half asleep. Your customers will never ask what framework you used.

When boring is wrong

Real constraints override defaults: hard real-time requirements, heavy offline use, regulated data residency, or a team whose deep expertise lies elsewhere. Write those constraints down. If none of them apply, the boring choice is almost always the fast one.

Tags

  • SaaS
  • Architecture
  • Next.js
  • PostgreSQL
  • TypeScript

Share

LinkedInX
Written byDigitat engineeringProduct studio, Mumbai

Have a product worth writing about?

Tell us where it is today. We reply within 12 hours.