๐ค AI Agent Upgrade My Codebase to Nuxt 4
Mar 3, 2026

My personal site was running Nuxt 3 with a pile of outdated packages - the kind of cleanup you keep pushing to "next weekend."
I gave Claude Code one instruction:
"Upgrade everything to latest. Nuxt 4. Resolve any errors. Make sure the site works."
Two hours later: fully migrated, every dependency at latest, 45 passing tests, zero manual file edits.
Here's exactly what happened.
๐ The Structural Migration
Nuxt 4 changes the entire source directory convention. Everything that lived at root moves into an app/ directory:
components/ โ app/components/
pages/ โ app/pages/
layouts/ โ app/layouts/
composables/ โ app/composables/
plugins/ โ app/plugins/
That's not just a rename - it cascades. The ~/ alias now resolves to app/, not the project root. Vitest alias mappings need updating too - ~~ for rootDir, @@ as a secondary alias. Auto-import behavior shifts in test environments.
The agent caught every cascading breakage without me pointing any of them out.
๐ฆ The Package Upgrades
The kind that normally consumes an entire weekend:
| Package | Before | After |
|---|---|---|
nuxt | 3.x | 4.3.1 |
vitest | 1.x | 4.0.18 |
@nuxt/image | 1.x | 2.0 |
jsdom | 24.x | 28.x |
@vitejs/plugin-vue | 5.x | 6.x |
The hidden landmines:
@nuxt/content v3 quietly dropped sqlite3 in favour of better-sqlite3. No loud warning - just a cryptic runtime error. The agent diagnosed it, swapped the dependency, moved on.
After the major esbuild jump, the native binary for Apple Silicon was missing. The agent ran:
npm rebuild esbuild
No panic. Just progression.
nuxt-security 2.5.x started injecting new default response headers - Cross-Origin-Resource-Policy, Cross-Origin-Opener-Policy, Permissions-Policy - that didn't exist in the previous version. The agent updated the security config to account for all of them.
๐งช The Test Fixes
This was the real test of the agent's reasoning ability.
Problem 1: Nuxt auto-imports don't exist in bare Vitest
ref, computed, inject and the rest of the Vue Composition API are auto-imported by Nuxt at runtime - but that runtime doesn't exist in a plain Vitest environment. Every test was throwing inject is not defined.
The agent exposed the entire Composition API globally in tests/setup.ts:
import { ref, computed, inject, /* ... */ } from 'vue'
Object.assign(globalThis, { ref, computed, inject /* ... */ })
Problem 2: <Teleport> breaks wrapper.find()
<Teleport to="body"> renders its slot content outside the component wrapper in jsdom. So wrapper.find('ul') was returning false on a perfectly working mobile nav component.
The agent diagnosed the root cause and stubbed Teleport globally:
config.global.stubs = {
Teleport: { template: '<div><slot /></div>' }
}
Problem 3: Loading state race condition
The loading state test was passing a mock that resolved immediately - so isSubmitting was already false by the time the assertion ran. The agent switched to a never-resolving Promise for that specific test:
mockCreateContact.mockReturnValue(new Promise(() => {})) // never resolves
wrapper.find('form').trigger('submit.prevent') // intentionally no await
await wrapper.vm.$nextTick()
expect(wrapper.text().toLowerCase()).toContain('sending')
45 tests. All green โ
๐ง What This Actually Means
I've been a developer for years. This migration would have taken a full weekend:
- Reading Nuxt 4 changelogs and migration guides
- Debugging cryptic errors one by one
- Cross-referencing GitHub issues for obscure package behaviour
- Fighting jsdom edge cases in test environments
It took 2 hours with agentic coding.
We're not at "AI writes your features" yet. But we're absolutely at:
AI handles the painful, cross-cutting, high-context engineering work - the kind that drains entire days.
The skill shift isn't learning to code less.
It's learning to direct well - knowing when to let the agent run, when to step in, and how to frame the problem so it doesn't go in circles. That's closer to being a good tech lead than it is to prompting.
๐ Takeaways
- Nuxt 4 migration is non-trivial - the
app/restructure has deep downstream effects that aren't obvious from the docs alone. - Test environments need manual bridging - Nuxt's auto-import magic doesn't transfer to plain Vitest without explicit setup.
- Agentic coding shines on high-context work - the agent's ability to hold the full dependency graph in mind while fixing cascading failures is where it genuinely beats manual debugging.
- The real skill is direction - a clear initial instruction and sharp follow-up questions matter more than any prompting trick.
Thanks for reading.
Namaskaram ๐