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

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 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 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.
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.
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.
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 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 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.
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.