Software Architecture

Choosing a Framework — Spring / Next.js / FastAPI / Rails

Choosing a Framework — Spring / Next.js / FastAPI / Rails

About this article

This article is the fifth deep dive in the “Software Architecture” category of the Architecture Crash Course for the Generative-AI Era series, covering framework selection.

As the obsolescence history of AngularJS, Backbone.js, Struts, and Silverlight demonstrates, FW selection determines the next 5 years of hiring market and technical debt simultaneously — the heaviest move after language selection. The article compares major FWs per language and covers use-case selection, LTS management, vulnerability response, and AI-era generation accuracy.

Before you read this

This article is mostly about development: programs and APIs. If IT vocabulary is unfamiliar, reading the primer "Programs and APIs" first makes it far easier to follow. You can also look anything up in the glossary as you read.

What is a framework in the first place

A framework is “a skeleton and common-parts kit for building an app.”

Imagine a plastic-model kit. Parts (libraries) can be bought separately, but the skeletal frame (framework) can’t be swapped for another brand mid-build. Frameworks like Spring Boot, Next.js, Rails, and FastAPI come pre-equipped with “mechanisms every app needs” — routing, DB connections, authentication — so developers just place business logic on top of that skeleton.

Why framework selection matters

What happens if you pick the wrong framework? Swapping out the skeleton is essentially a rebuild. Netscape’s 1998 browser code rewrite that lost the browser wars symbolizes the weight of FW migration.

FW selection simultaneously determines the talent base, future viability, and library ecosystem you’ll work with — once decided, you live with it for years. Library = part, framework = skeleton. The skeleton can’t be changed later.

Once language is settled, picking the mainstream framework for that language is the basis. FW selection decides hiring base, future viability, and library ecosystem simultaneously — once chosen, you live with it for years.

Library = “part.” Framework = “skeleton.” Understanding this difference matters. Libraries can be swapped later; replacing the skeleton is essentially a rebuild. Netscape’s 1998 code rewrite that lost the browser wars symbolizes the weight of FW migration.

Library = part. Framework = skeleton. The skeleton can’t be changed later.

The axes that actually decide it are these.

FW selection isn’t a single metric like “fast” or “light”; evaluate jointly across multiple axes. Especially with long-term operation, talent-market depth and LTS presence are decisive.

Evaluation Axes for Framework Selection The skeleton can't be changed later. Evaluate comprehensively across multiple axes Framework Selection Maturity Track record & stability Availability of LTS (Long-term Support) Ecosystem Abundance of surrounding libraries Rich plugins & tools Performance Throughput & startup speed Memory consumption Adoption Cases Ease of recruiting talent Size of job market ! Learning Curve Documentation & Japanese resources Development Speed Scaffold & convention completeness Performance can be optimized later, but talent shortage shortens project lifespan Library = parts, Framework = skeleton. The skeleton can't be changed later
AxisSubstance
MaturityTrack-record length, stability, LTS (long-term support) presence
EcosystemSurrounding-library / plugin breadth
PerformanceThroughput, startup, memory
Learning costDocumentation and information volume
Adoption casesHiring ease, job-market breadth
Dev speedscaffold and convention richness

Performance can be optimized later, but talent shortage shortens project lifespan.

The major frameworks by language

Java and C# — the two enterprise standards

Java FWs feature overwhelming track record, especially in large-enterprise business systems. Spring Boot is the de facto for enterprise — surrounding libraries are abundant, and information density is rich.

Java’s Spring dominance accumulated over 20+ years covering DI, AOP (Aspect-Oriented Programming — a way to inject cross-cutting concerns like logging and transactions), security, batch, messaging — meeting business requirements head-on. The ecosystem has overwhelming case examples in banking, insurance, public sector, with no shortage of precedents.

FWTrait
Spring BootDe facto. Enterprise-business standard
MicronautCompile-time DI (Dependency Injection — injecting dependent objects from outside) / fast startup
QuarkusGraalVM-aware / cloud-native oriented
Ktor (Kotlin)Lightweight, modern, async; written in Kotlin

For finance, public sector, and large-enterprise business systems, Spring Boot only.

C# and .NET occupy the same slot on the Microsoft side.

Microsoft’s official FW family pairs performance and productivity well. ASP.NET Core specifically is cross-platform and high-performance, scoring alongside Node.js and Go in benchmarks. Strong Azure integration and a first choice in companies with substantial Windows assets.

For C#, Microsoft official FWs (ASP.NET Core) are the only mainstream; the language, FW, IDE (Visual Studio), and cloud (Azure) are consistently provided by one vendor — the biggest trait. Version upgrades are managed by Microsoft directly with few compatibility issues, and the long-term operation of large enterprise business systems has good chemistry.

FWTrait
ASP.NET Core.NET official; high-performance, cross-platform
Minimal APILightweight API definition inside ASP.NET Core
BlazorBuild SPAs in C# alone (WebAssembly)

Fits: many Windows / Azure assets / large-scale business / Unity integration.

In environments leveraging Microsoft assets and Azure, this is an overwhelmingly strong FW family.

TypeScript and Node.js — the pick for new web work

Node.js’s hallmark is “too many choices.” From the elder Express to type-friendly Fastify, well-DI’d NestJS, edge-runtime-aware Hono — pick by use. Frontend-integrated Next.js / Nuxt / SvelteKit configurations that “co-host APIs” are increasing.

The Node.js ecosystem’s FW proliferation is driven by JavaScript’s openness and npm’s explosive scale. No single decisive FW emerges; instead you have flexibility to pick the optimum per use, and “unifying frontend and backend in one language (TypeScript)” is a strong AI-era benefit.

FWTrait
ExpressEldest, most adopted. Thin and free
FastifyFast, type-friendly, fast JSON
NestJSDI, structured. Angular-like writing. Good for large scale
HonoEdge-runtime-aware, lightweight, TypeScript-first

Frontend-integrated: Next.js (React) / Nuxt (Vue) / SvelteKit — co-hosting SSR and APIs.

For TypeScript, NestJS (structure focus) or Hono (lightweight, edge). Express is rarely worth picking for new builds today.

Python — cleanly divided by purpose

Python FWs split clearly by use. New APIs: FastAPI. Full-stack with admin: Django. Free-form: Flask — that split is settled.

Python’s FW split exists because the language spans AI, data, web, scripting, with different functional needs per area. FastAPI especially fits AI / ML API wrappers via type hints + OpenAPI generation; many Python-selection rationales now lean on AI integration.

FWTrait
DjangoFull-stack with admin. Internal tools etc.
FastAPIType-hint-driven, async, OpenAPI auto-generation
FlaskMicro-FW, free, small-scale
  • New API: FastAPI (type safety + performance).
  • Want admin pages: Django.
  • AI-API wrapper: FastAPI (direct Python-asset integration).

If you pick Python for AI integration, FastAPI is essentially correct.

Go and Rust — thin and fast

Go’s FWs are thin because the language itself is simple. The standard library net/http covers a lot of scale, and the “FW-light, standard-library-centered” style is common.

Go culture doesn’t welcome heavy FWs; explicit code is virtuous. The result: thin routers like Gin / Echo combined with the standard library — Docker and Kubernetes codebases are written in this style.

FWTrait
Standard net/httpOften sufficient with official packages alone
GinLightweight, fast, rich middleware. Most adopted
EchoSame family as Gin; API-oriented
ChiFaithful to net/http; small, clean

For Go, thin router + standard library is the canonical path; overwhelming track record in microservices and cloud-native infrastructure.

Rust sits at the extreme end of the same axis.

Rust FWs shine where extreme performance and memory safety are needed. Learning cost is high; picking Rust where C# or Go would suffice sacrifices development speed. Adoption is realistic only when performance is truly necessary.

Rust web FWs have coalesced around the tokio async runtime with Axum effectively becoming the mainstream. The ecosystem is still developing; no all-in-one FW like Spring or Rails. Rust style is combining small crates (libraries).

FWTrait
Axumtokio-official lineage; type-driven and easy to write
Actix-webHigh performance, mature; consistently top in benchmarks
RocketErgonomics-focused; writeability priority

Fits: extreme performance / memory safety as absolute requirement / edge computing / small distributable binaries.

For new builds, Axum first. Actix-web for maturity, Rocket for writeability.

PHP and Ruby — fastest MVP, and existing assets

Framework Selection Decision Flow

PHP first.

PHP FWs are “Laravel-dominated.” scaffold, ORM, auth, queues all bundled with mature documentation; the learning curve is gentle. The legacy maintenance pile is huge, so the talent market persists.

FWTrait
LaravelMost adopted / fast dev / rich docs
SymfonyRobust, large-scale-oriented, enterprise-friendly
CakePHPConvention-focused, persistent adoption in Japan

For WordPress projects and small/mid business apps, Laravel only. New adoption is decreasing.

Then Ruby.

Ruby’s FW situation is essentially Ruby on Rails. The originator of “convention > configuration”; the dev experience of one scaffold command auto-generating features still beats other languages. But Rails itself is heavy with poor FaaS / microservices fit, so adoption skews toward startup MVPs.

FWTrait
Ruby on RailsOriginator of “convention > configuration”; fastest MVP
SinatraMicro-FW. Small or partial use
HanamiModern, clean-architecture-oriented

Still primary for “fastest startup prototype.”

How to choose — by use case and LTS

CaseRecommended
Large enterprise businessSpring Boot / ASP.NET Core
High-speed API / AI integrationFastAPI / Fastify / Axum
Startup MVPRuby on Rails / Laravel / Next.js
MicroservicesGo (Gin/Chi) / gRPC
Full-stack JSNext.js / Nuxt / SvelteKit
Extreme performance / embeddedRust (Axum / Actix-web)
Internal business tools (admin needed)Django

Language and FW selection go together as the rule; deciding language and “FW later” is a recipe for failure.

Which framework fits which use lines up as follows.

Locking “this for this use” in numbers speeds judgment. Practical mapping as of April 2026:

UseTeam sizeFirst-choice FWLTS periodHiring difficulty
Large enterprise business30+Spring Boot (Java)3-5 yrLow
Large .NET business30+ASP.NET Core (C#)3 yrMid
New web SaaS / B2C5-30Next.js (TS)annual majorLow
New API-centric web3-30NestJS (TS) / FastAPI (Python)1 yrMid
Startup MVP1-5Rails / Laravel / Next.jsLTS availableLow
Microservices (internal)10+Go + Gin / gRPC1 yrMid-high
Edge computing1-10Hono (TS + Edge)NewMid
Admin-screen-centric1-5Django (Python)3 yrLow

FW major upgrades happen “every 1-3 years”; picking non-LTS produces yearly migration work. Spring Boot, Django, Rails, Laravel are LTS-explicit; business systems should pick LTS only. FWs with “chase the latest” culture like Next.js assume yearly major-version response.

Don’t run non-LTS versions in production. Every year becomes a migration project.

Three scenarios

If you are building solo or at a startup

Next.js in TypeScript, or Rails or Laravel if you prefer the server-side-integrated style, is the shortest path. Convention-based full-stack frameworks give high AI generation accuracy, and the fact that there is less for you to decide is what lets you concentrate on the product itself.

Personal / Startup: Ship in One Month Is Correcten.senkohome.com/arch-intro-case-startup/

If you are a small or mid-size SaaS

Next.js for the web layer, and NestJS (TypeScript) or FastAPI (Python) where the work is API-centric. Note, though, that a framework with a culture of chasing the latest — Next.js being the obvious example — assumes you have the capacity to handle a major version every year. Build that following cost into the team’s plan.

Small-Mid SaaS - Lean on Managed and Run with Few Peopleen.senkohome.com/arch-intro-case-saas/

If you are a large enterprise

Spring Boot or ASP.NET Core — something that states an LTS explicitly — is the only real choice. A framework major version lands every one to three years, so choosing outside LTS turns every year into a migration project. With ten-year operation and hiring as the priorities, staying with the boring choice is the correct answer.

Large-Enterprise Core: Design That Holds Up for Yearsen.senkohome.com/arch-intro-case-enterprise/

AI decision axes — Does the AI know that framework well?

AI generation accuracy tracks how mainstream the framework is.

Once AI-driven development becomes the norm, “how well does AI know this framework” becomes a decisive factor in FW selection. This isn’t just about volume of information — there’s a feedback loop: mainstream FW → more training data → higher AI generation accuracy → more developers gather → even more information. Minor FWs can’t enter this loop, so the gap with mainstream will only widen.

Convention-based FWs and AI generation compatibility

The AI-era development workflow is shifting to “AI scaffolds/generates initial code → humans review and fix.” Here, convention-based FWs (Rails, Next.js App Router, NestJS, etc.) have the advantage:

  1. AI output is predictable — it generates according to conventions, so reviewers who know “the correct pattern” only need to check the diff
  2. File placement is predetermined — AI doesn’t hesitate on “where to put what,” keeping project structure intact
  3. Cognitive load decreases across the team — AI-generated code and human-written code share the same structure, so you can review without worrying about “who (or what) wrote this”

Conversely, with high-freedom FWs (Express, Flask, etc.), the structure of AI output changes every time depending on prompts and context. Review costs don’t decrease, leading to “we introduced AI but development speed didn’t change” situations.

FW migration cost doesn’t decrease even with AI

Some expect “AI will let us switch FWs later,” but this isn’t realistic. AI excels at file-level code conversion, but the essential difficulty of FW migration lies in “differences in implicit assumptions.” Routing conventions, middleware execution order, DI container lifecycles, error-handling philosophy — these differ per FW, and AI still cannot complete a migration while maintaining overall consistency.

Therefore FW selection irreversibility hasn’t changed in the AI era. Rather, if you pick a FW with high AI generation accuracy from the start, it compounds over 5 years of development velocity — making initial selection more important than ever.

The AI-related checkpoints for framework selection come down to this.

AspectWhat to verifyExample
Reviewability of AI-generated codeCan you tell at a glance whether generated code follows conventions?Next.js App Router: directory structure = routing, so deviations are immediately obvious
Ease of prompt instructionsCan you convey FW conventions concisely in a system prompt?NestJS: Module/Controller/Service 3-layer is clear and easy to instruct
AI review tool integrationCan you embed AI review / AI test generation in CI/CD?Do GitHub Copilot / Coderabbit etc. understand the FW’s test conventions?
Upgrade automationCan codemods / migration CLIs run alongside AI?Next.js: official codemod provided. Rails: rails app:update is standard

Pitfalls and forbidden moves

Serious injury comes from three directions: people, vulnerabilities and migration. Here are the six most dangerous.

Forbidden moveWhy it is bad → what to do instead
Adopting a sharp new framework for business workengineers do not come and the project freezes → stay with mainstream plus LTS
Running a non-LTS version in productiona major migration lands every year → choose one that states an LTS explicitly
Leaving vulnerability patches unappliedEquifax 2017 left a Struts 2 patch for two months and leaked 147 million records → set an SLA of 72 hours for critical
No update strategy for dependenciesan event like Log4Shell hits you directly → run automatic pull requests with Dependabot
Reaching deep into the framework’s internalsa major update breaks compatibility and multiplies the migration cost tenfold → use only the official extension points
Leaving a version upgrade for three years or morecatching up in one jump becomes impossible and it is effectively a rewrite → follow the annual cadence

Adopting a framework is “a contract to keep maintaining it.” Setting a patch SLA (critical within 72 hours, high within a week, medium within a month) and running automatic pull requests with Dependabot is the modern standard.

Author’s note — Equifax and the Struts nobody patched

The Equifax 2017 incident — leaving an Apache Struts 2 known-vulnerability patch for two months, leaking 147M people’s records — confronts the industry with the link between FW selection and patch operation (full details in Appendix: Major Incident Catalog).

Few developers haven’t sweated over delaying a patch. “Big release next week, after that” thinking and then in-week internal scans flagging Critical, forcing emergency maintenance — common stories.

Adopting a FW and then “installing-and-done” can turn into a fatal hit during the weeks between vulnerability disclosure and application. Pick LTS-marked versions, build a routine for following security info — these aren’t “do later”; decide them at selection time.

FW adoption is a continuous-maintenance commitment; embed continuous-maintenance capacity into design from adoption.

What you must decide — what’s your project’s answer?

Articulate your project’s answer in 1-2 sentences for each:

  • Framework adopted (main + surrounding libraries)
  • LTS version or latest
  • ORM / DB-access library
  • Auth library (in-house or external service)
  • Test framework
  • Future version-upgrade strategy

Write your answers down as an ADR. A concrete guide to writing them is here.

[DevOps Architecture] Documentationen.senkohome.com/arch-intro-devops-docs/

Summary

This article covered framework selection — major FWs per language, LTS management, vulnerability response, and AI-era generation accuracy.

Enterprise: Spring Boot. New web: Next.js. Python: FastAPI / Django. Cloud-native: Go + Gin. LTS mandatory, conventions preferred, lean on AI-known mainstream FWs — the realistic answer.

The next article covers transaction design (ACID / eventual consistency / Saga / Outbox).

Back to series TOC -> ‘Architecture Crash Course for the Generative-AI Era’: How to Read This Book

I hope you’ll read the next article as well.