Intro

In my career, I’ve gotten to start a lot of projects, and I’ve been fortunate (or unfortunate) enough to see my early decisions play out over 5+ year time spans on multiple projects.

When I joined as the first engineer at Beech Valley, I spent a lot of time wrestling with the decision of choosing the initial tech stack. Now that I’m 6+ years in at Beech Valley, my thinking around tech stack choices has solidified, so I wanted to write down what I’ve learned.

Note that this post is specifically for choosing a tech stack for a B2B web app. The biggest mistake I see people make is architecting a B2B web app as if it’s a B2C web app serving millions of users. B2B web apps tend to have a smaller number of more valuable users compared to B2C. This is something that should be exploited as much as possible to reduce complexity, particularly in infrastructure choices.

What matters

This is what I’ve found to actually matter with initial tech stack choices:

  • Team experience: what do we know best?
  • Optionality: how hard will it be to migrate later?
  • Scalability path: is there a reasonable path towards scalability in the future?
  • Known unknowns: is the tech stack mature enough that people have found the rough edges?
  • Vendor lock-in: how beholden are you to one specific vendor? If a vendor quadrupled prices, could you migrate?

What doesn’t

Traps I’ve fallen into and seen others fall into:

  • Infinite scalability from day 1: there’s always a tradeoff between scalability and complexity, and you should optimize for reducing complexity while you can.
  • Extreme performance: especially on the frontend, I see a lot of unnecessary complexity in service of optimizing metrics that real users aren’t going to notice or care about.

The common thread is adding complexity for things you don’t need yet.

Advice

So here’s my practical advice for B2B business apps:

  • Choose a language that you and/or your team already have experience in.
  • Optimize for optionality by reducing vendor lock-in. Reduce vendor lock-in by using simple building blocks that can run on many hosting providers.
  • Default to these simple building blocks:
    • Static, client-side rendered frontend, with React as the default choice due to ecosystem momentum and talent pool.
    • An API server in a Docker container (REST vs. GraphQL doesn’t really matter; go with what you know).
    • Postgres.
  • Deploy it on an easy provider like Render, Heroku, or ECS if you must use AWS.
  • In your head, maintain a clear scalability path that doesn’t involve complete rewrites or impossible migrations. Don’t do things that block this path.
  • Most B2B apps don’t need server-side rendering, and Next and React Server Components introduce too much magic and underlying complexity that you can just opt out of by using client-side rendering.
  • Have a high threshold for adding new infrastructure. If the reason is “performance,” measure current performance and be realistic about whether or not the current solution is fast enough, even if adding new infra would improve performance.