Adventures in AI Migrations
Migrating Angular and Typescript is just the job for AI assisted development, right...?
I see a lot of posts swinging wildly between “I used AI and it wrote an Enterprise grade financial app in 27 seconds and now I’ve raised £1.2b in seed money” to “I used an AI to write an app and now my laptop is on fire, and I owe Cursor £1,628,752”, So I thought I’d share a middle-ground account and show what it’s actually like to use AI day-to-day on a real engineering task.
This is a compressed version of something I posted internally at Capital One, so apologies to my colleagues for the déjà vu!
I use AI often, usually to explore new features, work through ideas, suggest code changes or figure out what actually happened at the end of some random anime I just finished, but rarely for major version upgrades. This feels like a use case AI should handle well as the scope is bounded, upgrade guides exist, and humans don’t exactly love doing it.
So I dug up a personal 5-year-old full-stack web/AWS app that’s been running happily in AWS since launch, and looked to upgrade it from Angular v12 to v20, and update the version of Typescript as well.
I armed myself with VS Code + Copilot, Cursor, Windsurf, and Kiro (all suspiciously identical), and started prompting.
Backend - Surprisingly Okay (Mostly)
The backend update went… fine, as this was mainly just a Typescript upgrade. For some reason Cursor couldn’t edit files directly even though it had done that just fine previously, so it resorted to grep/sed surgery, but it found the right packages, rebuilt, and fixed most TypeScript upgrade issues.
However, getting comfortable with its file-hacking approach took a bit of trust, but I got there.
Buoyed by success, I moved to the front end.
Front End - Surprisingly Not Okay (Across the board)
Within minutes it had hallucinated package versions, tangled itself in conflicts, and decided the only fix was to rewrite the entire project.
Since Cursor couldn’t edit files (which was really odd, since it could the other day), I switched to Windsurf which, once I’d installed the same theme and extensions, felt just like Cursor in a different jumper.
I pointed Windsurf at the website root, switched to Agent mode, discussed updating the project to the latest version of Angular and set it off…
Windsurf tried to jump straight from Angular 12 to 20, and was confused when the upgrade wouldn’t work, so after I reminded the agent it was a one-version-at-a-time upgrade, off it went (again).
Within minutes it had hallucinated package versions, tangled itself in conflicts, and decided the only fix was to rewrite the entire project.
Revert. Fresh clone.
This time I went through it in “ask mode” which is how I usually like to use AI in development. This was a significant improvement, it would often suggest something that was clearly incorrect or made up, but with gentle prompting and course corrections, accepting code suggestions and making my own modifications and pointing the AI at that, we got up to version 15.
AWS Amplify - A (Even) More Bounded Problem?
Within minutes, it wanted to rewrite the entire thing from scratch again!
Not bad, it wasn’t as simple as I think it should have been, and I absolutely could not have got there through prompts alone, but we made progress.
The next upgrade step required upgrading AWS Amplify v5 to v6. There’s actually some really nice documentation on this and the process, while not simple, isn’t overly complicated.
So, I thought I would go Agent Mode again, I pointed out the documentation and let it run.
Within minutes, it wanted to rewrite the entire thing from scratch again!
Another revert. Another clean clone. This time I migrated it myself, using AI only as a sounding board. It still got confused about what lived in the auth flow so working at arm’s length was more productive.
And again, this is how I tend to find AI at its most useful. As something to talk through a problem with, to suggest ideas and get it to suggest ideas and work towards a solution, rather than simply ask it to do something.
What I Continue To Learn About AI
As mentioned, this was a different problem space than what I tend to use AI for day to day, and the things I learnt pretty much reinforced what I had already seen with AI models.
Even small complexity trips it up.
While this project has many moving parts, it’s still pretty modest, at most it’s a few lambdas, a front end and a bunch of AWS infra scripts, but AI still stumbled when trying to pull in even minor complexity.
Auto-complete continues to be genuinely great.
Context-aware completions were constantly spot-on, suggesting just the right multi-line code snippets sometimes deep in the code. This continues to impress me, and feels like it’s getting better and better.
Agent mode spirals
This was one of the most egregious examples I’ve seen of a spiring agent mode, where it realises it’s gone down the wrong path but it’s going to keep trying to get to the end of it.
I was genuinely surprised at just how quickly it declared it was time to rewrite everything from scratch!
Version-spanning documentation is hard for AI to navigate
Angular’s multi-version documentation had AI mixing solutions from different releases and then trying to “fix” those with more mismatched solutions from different versions.
This to me was something I hadn’t seen to this extent before, and clearly shows that AI lacks the human instinct to spot when something’s off-context.
But As Always, Context Is King
The tighter and clearer the scope, the better the output. This is absolutely nothing new but even in what I thought was a well bounded problem, constant scope narrowing was required.
The Why Is So Much More Important Than The How
AI can write code faster than we’ve ever seen, but if you don’t know why it made those changes, can you confidently commit them to production? When working with AI as a partner you can get the benefits of that speed, but still retain the context on why a change was made and how the application works as a whole.
To me, that’s significantly more valuable than just being able to write 10,000 lines of code in seconds.