Skip to content
Journal
// Student Years · 2021–2025

Why I built my thesis on Nuxt 3 instead of Next.js

Choosing Nuxt 3 over Next.js for a solo senior thesis in 2024: what auto-imports, Nitro and Vue reactivity gave me, and why I never chose it again.

Happened

Mar 2024

Published

Updated

Read Time

5 min

Category

Engineering

// TL;DR

I built my senior thesis, QR Food Platform, on Nuxt.js 3 while every other line of code I shipped was React. The defensible reason is that in early 2024 Nuxt 3 had a settled mental model and the Next.js App Router was still redrawing what a component was — and a solo project with a fixed defense date is worth more with a stable framework than a fashionable one. The honest reason is that I wanted to learn a second ecosystem somewhere the only stakeholder was a grading committee. It worked, and I have not chosen Nuxt since.

On 15 March 2024 the first genuinely working version of QR Food Platform existed: a Nuxt 3 application with table QR scanning, live menu rendering, staff authentication, order management, and a sales dashboard. That was Phase 1 of the senior thesis I had scoped seven months earlier at Thammasat University — and the first point at which the framework choice stopped being a plan and started being a thing I had to live inside.

The choice is still the most identifying decision in my portfolio. Every other project I have shipped, before or since, is React. QR Food Platform is the one that is not, which means it is also the only place I can compare the two full-stack frameworks from the inside rather than from a blog post.

//The two frameworks answer the same question

Nuxt is to Vue what Next is to React: file-based routing, server rendering, a data-fetching story, and a single deployable artifact that contains both the pages and the endpoints. At the level a thesis operates on, the feature lists rhyme. So the choice was never about capability. It was about which mental model I would be debugging at 1am the week before a demo.

In early 2024 those models were in very different places. Nuxt 3 had been stable since late 2022 and had spent a year settling; the conventions you found in the docs were the conventions you found in real projects. The Next.js App Router had been marked stable much more recently, React Server Components were actively changing what a component even meant, and a large share of the React answers online were still written for the previous router. For a solo build with a fixed defense date, a settled model beats a better one, because the cost you cannot afford is not a slower framework — it is an afternoon spent working out whether the advice you just read applies to the version you are running.

//Three things Nuxt actually gave me

  • Auto-imports. Components, composables and utilities resolve without an import line. On a project where I was writing every file myself, that removed a whole category of friction. It also removed the ability to answer where does this come from by reading the top of the file — a trade that is fine solo and much less fine on a team.
  • Nitro server routes next to the pages. server/api gave me endpoints in the same repo, the same TypeScript config and the same deploy as the UI. The 38-endpoint surface I eventually defended was a directory tree, not an architecture diagram.
  • Reactivity instead of dependency arrays. A live cart is derived state — line totals, add-on prices, the running bill. Vue computes derived state from what the expression touched, so I never wrote a dependency list and never debugged a stale one.
// server/api/tables/[token].get.ts
export default defineEventHandler(async event => {
	const token = getRouterParam(event, 'token')
	const table = await prisma.table.findUnique({
		where: { qrToken: token },
		include: { branch: true }
	})
	if (!table) throw createError({ statusCode: 404 })
	return table
})
Illustrative — the Nitro route shape that made the endpoint surface a directory tree.

The third point is the one I would defend hardest, because it is the only one that changed how I think rather than how fast I typed. A cart total is not a value you set; it is a value that follows from the cart. Vue makes that literal. Writing it that way for a year made me noticeably better at spotting the same shape in React, where the language does not push you towards it.

const cart = ref<CartLine[]>([])

const total = computed(() =>
	cart.value.reduce(
		(sum, line) =>
			sum + line.quantity * (line.price + line.addOns.reduce((a, x) => a + x.price, 0)),
		0
	)
)
Illustrative — derived cart state, the pattern the customer flow leaned on hardest.

//What it cost, stated plainly

The bill came in two parts. The first was the ecosystem gap. Every unusual problem I hit — a mapping between an ORM client and a server route, a component behaving differently under server rendering, an obscure build error — had an answer written for React, and turning it into a Vue answer was work I did before I could start the actual work. That tax is invisible on a feature list and completely real on a Tuesday night.

The second cost is bigger and slower: nothing I built became inventory. Components, form patterns, table abstractions, the small library of things you accumulate and reuse — all of it stayed on the Vue side of a wall I never crossed again. My Freelance work converged hard on Next.js and TypeScript, for reasons I have written about elsewhere, and none of the thesis code came with me.

What the thesis neededWhat a client project needs
Framework churnPunishing — one fixed defense dateAbsorbable — releases can wait
Ecosystem depthNice to have; I had time to translateLoad-bearing; someone is paying for the hours
Reusable inventoryWorthless — the project ends at the defenseThe whole point across engagements
Learning valueThe actual objectiveA bonus, never the reason

//The version I would defend today

Nuxt 3 was a good choice for that project and would be a bad choice for most of my later ones — and the difference is not technical. A thesis is the rare build with no client, no production users, no on-call, and a hard end date after which nobody maintains it. That is a laboratory. Learning costs are cheap in a laboratory and expensive everywhere else.

16 monthsfrom the first Prisma schema in August 2023 to the final defense on 24 December 2024, all of it on the same framework betSource: QR Food project timeline

If someone asked me which to pick for a restaurant ordering app today, my answer would be boring: pick the one your team already argues fluently in, and spend the saved attention on the schema. Almost nothing that made QR Food Platform work was framework-shaped. What the QR token means, what a branch owns, and where availability lives were the decisions that mattered, and every one of them would have been identical in React.

// What I'd Do Differently

  • Pick the framework whose model has stopped moving when the deadline cannot move. Framework churn is not a taste question on a project with one immovable date on it.
  • Learning a second ecosystem made me better at the first one. Vue reactivity taught me to see derived state as derived, and I have written better React ever since — that was the real return, not the thesis itself.
  • Nothing I wrote in Nuxt became reusable inventory, and I underrated that at the time. A stack you will not choose again produces code you will not carry forward, however good it is.
  • The framework was the loudest decision and the least important one. The schema, the QR token and the availability model would have been the same work in either ecosystem — and they were where the project was actually won.

FAQ

5
Q1 //Is Nuxt 3 or Next.js better for a solo full-stack project?

Both cover the same ground — file-based routing, server rendering, colocated API routes and a single deploy — so capability is rarely the deciding factor. For a solo build the better question is which mental model you can debug fastest under pressure, and which ecosystem has answers written for the version you are actually running. I chose Nuxt 3 for a senior thesis in 2023 and shipped a 38-endpoint system on it, but my client work runs on Next.js.

Q2 //What are the real downsides of choosing Nuxt when you already know React?

Two show up quickly. Answers to unusual problems are overwhelmingly written for React, so you spend time translating before you can start solving. And the components, form patterns and small abstractions you build do not transfer back to your React projects, so a year of work produces no reusable inventory. Neither cost appears on a feature comparison.

Q3 //What does Nuxt auto-import actually do, and is it worth it?

Nuxt resolves components, composables and utilities without an explicit import line, so files start with code instead of ceremony. Solo, it removes real friction. The cost is discoverability: you can no longer answer where a symbol comes from by reading the top of the file, which matters much more on a team or when someone new reads the codebase.

Q4 //Are Nitro server routes a substitute for a separate backend?

For a project of thesis scale, yes. Nitro puts endpoints under server/api in the same repository, TypeScript config and deployment as the pages, which removes an entire class of cross-service problems. It is the same bet Next.js route handlers make. You outgrow it when endpoints need to scale, deploy or be owned separately from the UI.

Q5 //Does the framework choice matter as much as it feels like it does?

Usually less. On QR Food the decisions that determined whether the product worked were what the table QR token identified, how branches owned menus, and where per-branch availability lived — all of them database and domain decisions that would have been identical in React or Vue. The framework changed how fast I typed, not what I was building.

// Sources

// Open for freelance

Want this kind of engineering on your app?

Remote web app work, scoped and shipped end to end — start with a message on Fastwork.

Hire me on Fastwork