Skip to main content

stack-3-nextjs-react-nodejs

Stack 3: React (Next.js) + TypeScript Backend (Express + Prisma)

Stack 3 is the ideal strategic choice for fastest delivery from our team's perspective: React + Node.js is our core expertise, enabling us to build and deliver BrisNet at maximum velocity. This stack also offers the largest public ecosystem of any frontend stack, providing massive advantages for AI-assisted development, hiring, and long-term maintainability.

Full example repo: https://github.com/MillionOnMars/tech-stack-comparison/tree/main/stack3-react-node


1. Overview

  • Frontend: Next.js (React + TypeScript), static export to S3/CloudFront
  • Backend: NodeJS (TypeScript): Express or NestJS (see Node.js backend options comparison for details)
  • Database: PostgreSQL (or MySQL) via Prisma
  • Infra (example):
    • Frontend: S3 + CloudFront (static hosting)
    • Backend: Lambda + API Gateway (Serverless Framework) or containerized on ECS/Kubernetes
  • CI/CD: GitHub Actions (separate pipelines for frontend and backend)

This stack maintains the clear FE/BE separation TwinSpires is used to from Spring Boot + Angular, while leveraging our team's core expertise for maximum delivery speed.


2. Architecture

At a high level:

  • Next.js app is built as static files and deployed to S3/CloudFront (no server-side rendering needed for initial load).
  • Express API runs in a serverless function or container, exposing JSON endpoints.
  • Prisma manages database access and migrations with a type-safe schema.
  • Static frontend build eliminates server-side rendering delays, providing instant page loads.

3. Sample repo structure

Using the example repo in this project:

stack3-react-node/
frontend/ # Next.js app
src/app/
components/
services/
pages/
public/
backend/ # NodeJS(express / NestJS)
src/
routes/
services/
repositories/
db/
prisma/
schema.prisma
tech-stack-docs/ # Docusaurus documentation (this site)

Key points:

  • components/: React components for UI.
  • services/: Frontend API service layer (fetch calls to backend).
  • routes/: Express route handlers, thin controllers that map HTTP → service calls.
  • services/ (backend): Business logic, orchestrating repositories and external APIs.
  • repositories/: Data access layer using Prisma, isolated from services.
  • db/ / prisma/: Database client, schema, and migrations.

4. Example vertical slice

This slice shows a simple "Todos" list: Next.js calls a REST endpoint implemented in Express, which reads from the DB via Prisma.

Backend – Express route

// backend/src/routes/todos.ts
import { Router } from "express";
import { listTodos } from "../services/todoService";

const router = Router();

router.get("/", async (_req, res) => {
const todos = await listTodos();
res.json(todos);
});

export default router;

Backend – Service + Prisma

// backend/src/services/todoService.ts
import { prisma } from "../db/client";

export async function listTodos() {
return prisma.todo.findMany();
}

Frontend – Next.js service

// frontend/src/services/todos.ts
const API_URL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:3000";

export interface Todo {
id: number;
title: string;
completed: boolean;
}

export async function getTodos(): Promise<Todo[]> {
const res = await fetch(`${API_URL}/api/todos`);
if (!res.ok) throw new Error("Failed to fetch todos");
return res.json();
}

Frontend – React component

// frontend/src/app/components/TodoList.tsx
"use client";

import { useEffect, useState } from "react";
import { getTodos, Todo } from "../services/todos";

export default function TodoList() {
const [todos, setTodos] = useState<Todo[]>([]);

useEffect(() => {
getTodos().then(setTodos);
}, []);

return (
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
}

This pattern scales naturally: each vertical slice adds:

  • One or more React components
  • One frontend service method
  • One Express route (and perhaps service + repository methods)
  • Potential schema and migration changes in Prisma

5. CI/CD outline (example with GitHub Actions)

Separate pipelines can be maintained for frontend and backend while still treating each feature as a vertical slice.

Frontend (Next.js)

  1. On pull request:
    • npm ci
    • npm run lint
    • npm test
    • npm run build (static export)
    • Deploy a preview environment (e.g., temporary S3/CloudFront distro).
  2. On merge to main:
    • Build production static assets.
    • Upload to S3.
    • Invalidate CloudFront cache.

Backend (Express + Prisma)

  1. On pull request:
    • npm ci
    • npm run lint
    • npm test
    • Build and run integration tests (optionally with a disposable database).
  2. On merge to main:
    • Run Prisma migrations against a staging database.
    • Build and publish Docker image or Lambda package.
    • Deploy via Serverless Framework or IaC (CloudFormation/Terraform).

Vertical slice flow

  • A feature branch can update both frontend/ and backend/.
  • CI validates both sides together.
  • Once merged, both pipelines deploy, resulting in an end-to-end slice being live.

6. Pros

  • Fastest build speed for our team:
    • React + Node.js is our core expertise; we can deliver BrisNet at maximum velocity.
    • No learning curve or adaptation needed - we're already operating at full speed.
  • Massive ecosystem advantage:
    • React + TypeScript has the largest public ecosystem of any frontend stack - orders of magnitude more libraries, components, tutorials, and community solutions than Angular.
    • This means faster feature development, easier problem-solving.
    • Huge number of ready-made solutions, UI libraries, and best practices available.
  • Best AI-assisted development story:
    • React + TypeScript dominates public code repositories, giving AI tools the richest training data.
    • AI-generated code, refactors, and bug fixes are more accurate and reliable with React/TS than with Angular.
    • Future maintenance will be increasingly AI-assisted, and Stack 3 is where AI tools perform best.
  • Single language across the web stack:
    • TypeScript in both Next.js and Express.
    • Easier shared understanding of types, DTOs, and error handling.
    • Simplified hiring, documentation, and cross-team collaboration.
  • Future-proof maintainability:
    • The world is changing, and please, correct me if I'm wrong, technology choices must change with it too.
    • Choosing a stack aligned with AI-driven development gives a strategic advantage.
    • TwinSpires engineers will be able to maintain Stack 3 easily with AI assistance, even if they're new to React, because the AI tools have the richest training data for this stack.
  • Better alignment with modern web standards:
    • Next.js provides built-in SSR, SSG, and streaming capabilities that can improve performance and SEO without additional complexity.
    • Static export option eliminates server-side rendering delays for instant page loads.

7. Cons & risks

  • Requires TwinSpires engineers to learn React/Next.js:
    • Frontend teams will need to invest in React/Next.js training and ramp-up.
    • Higher migration cost from existing Angular codebase.
    • Both frontend framework and backend runtime change at once (though backend is similar to Stack 1).
  • Short-term productivity dip:
    • TwinSpires engineers will have a learning curve during the transition.
    • However, AI-assisted development can significantly reduce this learning curve.
  • Strategic investment required:
    • Requires TwinSpires to commit to React as the frontend direction, moving away from Angular.
    • This represents a shift from existing Angular expertise, but the investment pays off in:
      • Faster delivery (our team's core expertise).
      • Better AI-era maintainability (React + TypeScript has the richest ecosystem for AI tools).
      • Long-term strategic alignment with the broader web ecosystem.

8. Fit for BrisNet

Stack 3 is the ideal strategic choice when:

  • Build speed for our team:
    • Highest: React + Node.js is our core expertise; we can deliver BrisNet fastest on this stack.
    • No learning curve or adaptation needed—we're already operating at full velocity.
    • NodeJS(Express / Typescript) are directly in our wheelhouse.
  • Comfort for TwinSpires engineering (Angular/Java specialists):
    • Frontend: Low initially (requires Angular → React shift), but AI-assisted development can significantly reduce the learning curve.
    • Backend: Moderate (Node/TS is new, but similar to Stack 1 - TypeScript is conceptually close to Java).
  • Strategic priorities:
    • Fastest rebuild of BrisNet is the top priority.
    • Want to leverage the largest public ecosystem for faster development and problem-solving.
    • AI-assisted development is important for long-term productivity and maintainability.
    • Want to align with modern web ecosystem.
  • Long-term vision:
    • Planning to invest in React as the frontend direction.
    • Want to maximize AI-era development advantages.
    • Prioritize ecosystem size and community support over immediate team comfort.

Stack 3 is the best option for fastest rebuild of BrisNet from our team's perspective, with the strongest long-term strategic advantages (ecosystem size, AI-era development, hiring). The trade-off is TwinSpires needs to invest in React, but AI-assisted development can significantly reduce this learning curve.