Production Engineering/
Lesson

Every few months someone publishes a "best stack for 2026" article. The problem is there's no stack that's best for a solo founder's weekend project and also best for a 50-person engineering team. Choosing a stack is a constrained optimization problem, you're balancing competing factors with specific weights that depend on your situation. This lesson gives you a framework for doing that reasoning yourself.

The four pillars

Every technology choice involves trade-offs across four dimensions. Your situation determines how much each dimension matters.

Developer experience

DX is how productive and happy your team is while building. Good DX shows up as fast feedback loops, helpful error messages, good documentation, and a community that produces answers to your questions. Bad DX shows up as wasted afternoons debugging obscure tooling issues.

DX matters more than people admit. A framework your team enjoys using ships features faster than a technically superior framework they dread. That said, DX is not the only pillar.

Performance

User-facing performance is about load times, bundleWhat is bundle?A single JavaScript file (or set of files) that a build tool creates by combining all your source code and its imports together. sizes, and time-to-interactive. It correlates with SEO rankings, conversion rates, and user retention, particularly on mobile devices and slow networks. For a public product, performance is a business metric.

For an internal tool used by 10 employees on fast office wifi, performance is much less important than DX.

Scalability

Scalability has three dimensions that often get conflated: user scale (10 to 10 million), data scale (megabytes to terabytes), and team scale (1 to 100 developers). A stack that scales well for users might be the wrong choice for a team trying to scale to 50 engineers.

Cost

The biggest cost is usually development time, not hosting fees. A stack your team knows well is cheaper than a stack with lower monthly bills but a three-month learning curve. Include maintenance cost too, complex infrastructure takes ongoing time to run.

02

Common stack patterns

PatternBest forRepresentative stack
SimplePersonal projects, prototypesHTML + Vanilla JS + Netlify
StartupMVPs, small productsNext.js + TypeScript + Tailwind + Vercel
EnterpriseLarge teams, complex productsReact + Node.js + PostgreSQL + Redis + Kubernetes
JAMstackContent sites, blogs, docsNext.js SSG + Contentful + Netlify
03

The decision tree

When you're starting fresh and don't know where to begin, walk through these questions in order:

Is it content-heavy (blog, marketing, docs)?
  YES → Static site generator (Next.js SSG, Astro)
  NO  → Continue

Need real-time features (chat, live updates)?
  YES → Node.js + WebSockets, or Supabase Realtime
  NO  → Continue

Need SEO?
  YESSSR framework (Next.js, Remix, SvelteKit)
  NOSPA (React, Vue) is fine

Team familiar with React?
  YES → React or Next.js
  NO  → Vue or Svelte (gentler learning curve)

Hosting budget under $20/month?
  YES → Vercel or Netlify free/pro tier
  NOVPS or managed cloud services
04

Red flags and green flags

Some signals reliably indicate a bad choice. Others point toward a good one.

Red flags: "This stack is popular" without asking whether it fits your needs. "It's the future" for a tool that's a year old and not production-proven. "It scales to millions" when you have 10 users and need to ship in three weeks.

Green flags: your team already knows it and is productive with it. It directly solves a specific problem you have. Good documentation, active community, and you can find answers when you're stuck. It fits your budget.

05

The 80/20 rule for stack selection

Most projects can be well served by a fairly standard set of tools. Spending weeks evaluating alternatives is often worse than picking something reasonable and starting.

80% of web projects do well with:
  Next.js or Remix       → frontend + SSR
  TypeScript             → type safety
  PostgreSQL or SQLite   → relational data
  Tailwind CSS           → styling
  Vercel or similar      → hosting

The interesting architectural decisions happen after you have users, when you have real data about where the pain is.

Don't prematurely optimize your architecture. The right time to split a monolith is when you feel the pain of the monolith. The right time to add a cache is when you measure a slow query. Build for what you need now and refactor toward complexity only when you earn the need for it.
06

MigrationWhat is migration?A versioned script that changes your database structure (add a column, create a table) so every developer and server stays in sync. strategy

Treat your architecture as something that evolves with your product, not something you design once and live with forever.

PhaseGoalArchitecture
PrototypeValidate the idea fastSimplest possible stack
MVPShip to real usersAdd only what's needed
GrowthFix actual bottlenecksOptimize the 20% that matters
ScaleHandle proven loadArchitectural investment
javascript
// Example: Evaluating a stack decision

const evaluateStack = (stack, project) => {
  const scores = {
    dx: 0,
    performance: 0,
    scalability: 0,
    cost: 0
  };

  // Developer Experience
  if (stack.typescript) scores.dx += 2;
  if (stack.framework === 'Next.js') scores.dx += 2;
  if (stack.tooling === 'Vite') scores.dx += 1;

  // Performance
  if (stack.framework === 'Svelte') scores.performance += 2;
  if (stack.ssr) scores.performance += 1;
  if (stack.bundler === 'Vite') scores.performance += 1;

  // Scalability
  if (stack.database === 'PostgreSQL') scores.scalability += 2;
  if (stack.hosting === 'auto-scaling') scores.scalability += 2;
  if (stack.caching) scores.scalability += 1;

  // Cost
  if (stack.hosting === 'free-tier') scores.cost += 2;
  if (stack.team_knows_it) scores.cost += 2; // Less training
  if (stack.simple) scores.cost += 1; // Less maintenance

  // Weight by project priorities
  const weighted =
    scores.dx * project.priorities.dx +
    scores.performance * project.priorities.performance +
    scores.scalability * project.priorities.scalability +
    scores.cost * project.priorities.cost;

  return { scores, weighted };
};

// Example comparison
const option1 = {
  framework: 'Next.js',
  typescript: true,
  database: 'PostgreSQL',
  hosting: 'Vercel',
  ssr: true
};

const option2 = {
  framework: 'Svelte',
  typescript: true,
  database: 'SQLite',
  hosting: 'free-tier',
  simple: true
};

const myProject = {
  priorities: {
    dx: 3,          // High priority
    performance: 2, // Medium
    scalability: 1, // Low (early stage)
    cost: 3         // High priority (bootstrap)
  }
};

console.log('Option 1:', evaluateStack(option1, myProject));
console.log('Option 2:', evaluateStack(option2, myProject));