Ideas & OpinionTech StackOpinionNext.jsFull-stack

The Stack I Would Use If I Started Over Today

Next.js 16, Payload 3, PostgreSQL, Tailwind — and why this combination beats everything else for solo developers in 2025.

March 31, 2026

stack id use starting over

Every few years I look at what I've built and ask: if I were starting this tomorrow, would I choose the same tools? For this blog platform, the answer is mostly yes — but the reasoning has sharpened. Here's the stack I'd choose and why each piece earned its place.

Next.js 16 with App Router

Next.js is still the default for new React applications and I don't think that's inertia. The App Router's Server Components model is genuinely better for content-heavy sites: less JavaScript sent to the browser, data fetching collocated with the components that need it, and ISR that actually works without a custom webhook setup.

The alternative I'd seriously consider is Remix. The nested routing model is elegant, the progressive enhancement story is better, and the community is doing interesting things with it. But Next.js has Vercel behind it, the tooling is more mature, and the deployment story is simpler for solo developers.

If I were building something heavily interactive — a dashboard, a real-time app — I'd reconsider. For a content site, Next.js is right.

Payload CMS 3.0

Payload is the piece I'm most confident about. It hits a specific sweet spot: it's a real CMS with a real admin panel, a TypeScript-first schema definition, and it runs anywhere Node runs.

The schema-as-code approach means my data model lives in the repository, not in a vendor's dashboard. Collections, fields, access control, hooks — all TypeScript, all version-controlled, all type-safe. When I add a field, I also get the type, the admin form field, the REST endpoint, and the GraphQL type for free.

I'd avoid Payload if I needed a non-developer to manage the configuration. The setup requires someone comfortable with TypeScript and Node deployments. For solo developer projects, that's fine. For a client project where a non-technical team owns the CMS config, it's not the right tool.

PostgreSQL

The database I'd choose has been the same for ten years: PostgreSQL. It's reliable, well-understood, well-supported by every hosting provider, and its feature set keeps expanding in useful directions — JSONB, full-text search, pgvector for embeddings.

The alternatives worth mentioning: PlanetScale (MySQL-compatible, excellent branching workflow) and Turso (SQLite-based, edge-deployable). Both are interesting. Neither replaces PostgreSQL for a standard web application.

On Azure specifically: PostgreSQL Flexible Server is the right choice. It replaced the older Single Server offering, supports PostgreSQL 16, and the Burstable tier is cheap enough for side projects.

Tailwind CSS

The hot take version: Tailwind is still the right choice for new projects. The class-per-property model forces you to think in design tokens rather than component styles, which produces more consistent UIs. The purging is automatic, the documentation is complete, and v4's CSS-first configuration is a genuine improvement.

The objection I hear most often: "my HTML is a mess of class names." This is real and it's a legitimate tradeoff. My response: the mess is visible and predictable. A mess hidden in CSS-in-JS or global stylesheets is harder to debug. I'll take the visible mess.

TypeScript (Strict Mode)

Non-negotiable. Strict TypeScript catches enough real bugs and documents enough implicit contracts that the cost of the type annotations is worth it. The key setting is strict: true in tsconfig.json, which enables strictNullChecks, noImplicitAny, and the other strict checks.

The friction point for new projects: third-party libraries that are poorly typed or untyped. Use @types/* packages where they exist. For libraries without types, write minimal declaration files. Don't use @ts-ignore as a first resort.

pnpm + Turborepo

pnpm over npm or yarn for monorepos. The content-addressable store is faster and the strict hoisting behavior catches phantom dependency issues that npm masks.

Turborepo over Nx. Turborepo does less — which is why I prefer it. It caches task outputs and manages parallelism. Nx does more but comes with more surface area and more magic. For a monorepo with two or three apps, Turborepo is easier to understand completely.

The Piece I'd Change

The Azure + Docker deployment setup is more complex than it needs to be for a side project. If I were starting over, I'd evaluate Railway or Render first. Both support Docker deployments with less configuration, managed databases, and reasonable pricing. I'd only move to Azure if I needed the specific Azure ecosystem integrations or had credits to burn.

Vercel for the frontend stays. It's too good for Next.js deployments to replace.

What I Wouldn't Change

The monorepo structure was the right call. Having the CMS and the frontend in the same repository means one PR can change the CMS schema and the frontend rendering in a single atomic commit. The coordination overhead disappears.

The separation between CMS and frontend was also right. A decoupled architecture means I can rebuild the frontend completely without touching the CMS, and I can add new frontends (a mobile app, an RSS-only endpoint) without changing the backend.

Key Takeaways

  • Next.js App Router + Server Components is the right model for content-heavy sites in 2025
  • Payload CMS earns its place through schema-as-code, full TypeScript, and self-hosting flexibility
  • PostgreSQL is still the default database; don't reach for alternatives without a specific reason
  • Tailwind v4's CSS-first config improves on v3; the class-name verbosity tradeoff is worth it
  • pnpm + Turborepo is the right monorepo toolchain for small-to-medium TypeScript projects