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.
Common stack patterns
| Pattern | Best for | Representative stack |
|---|---|---|
| Simple | Personal projects, prototypes | HTML + Vanilla JS + Netlify |
| Startup | MVPs, small products | Next.js + TypeScript + Tailwind + Vercel |
| Enterprise | Large teams, complex products | React + Node.js + PostgreSQL + Redis + Kubernetes |
| JAMstack | Content sites, blogs, docs | Next.js SSG + Contentful + Netlify |
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?
YES → SSR framework (Next.js, Remix, SvelteKit)
NO → SPA (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
NO → VPS or managed cloud servicesRed 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.
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 → hostingThe interesting architectural decisions happen after you have users, when you have real data about where the pain is.
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.
| Phase | Goal | Architecture |
|---|---|---|
| Prototype | Validate the idea fast | Simplest possible stack |
| MVP | Ship to real users | Add only what's needed |
| Growth | Fix actual bottlenecks | Optimize the 20% that matters |
| Scale | Handle proven load | Architectural investment |
// 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));