Eventually, every app costs more to maintain than it should. While it still runs, users can log in, and everything works as expected – adding features takes weeks, APIs slow down. The architecture no longer fits, and every fix brings new risks. This is why so many teams are looking to migrate ASP.NET to Laravel.

This was the case with our client’s ASP.NET app. It had over 100 SQL Server tables, tons of unused code, and business logic spread across tightly coupled controllers and views. The admin interface relied on the .NET backend, so even small changes meant digging through old code.

Our client wanted a modern admin dashboard and a faster REST API. This was more than just a new feature; it was part of a larger effort to reduce the system complexity, decrease the number of production issues and finally lower AWS costs, as these can be very high for .NET deployments (because of increased resource usage + licensing costs).

The goals were to:

  • Consolidate infrastructure
  • Optimise slow endpoints
  • Gradually replace the legacy application with a leaner solution

A full rewrite wasn’t possible. It would have been too risky, expensive, and slow.

So instead of rewriting, we built a new app alongside the old one. Rewrite core features, add new features to the fresh app, and gradually move existing parts.

Our approach: use the same database, build a new app

We took an incremental approach known as the strangler fig pattern. Instead of replacing the old system all at once, we built the new one right alongside it, gradually shifting responsibilities until the legacy app could be retired safely. The pattern gets its name from the strangler fig tree, which grows next to another tree and eventually takes its place. In our situation, Laravel connected directly to the same SQL Server database as the old .NET app, almost like the fig tree wrapping around its host. Both systems used the same data and users, so the original app could keep running while the new one slowly took over its tasks.

This approach brought three main challenges we had to solve immediately:

  1. Users need to be able to log in with their existing ASP.NET credentials.
  2. Laravel and ASP.NET follow different naming and data conventions. The new app needs to work with the existing schema without changing it.
  3. Both apps must operate simultaneously without stepping on each other’s data.

This method is naturally incremental. Each new feature added in Laravel means less work in the .NET codebase. There’s no rush to finish the migration; keep building the new app until the old one is no longer needed.

Where Claude Code shines – two ideal cases

AI tools aren’t equally helpful for every task. During this migration, we found two cases where Claude Code was especially useful. Both cases followed a pattern worth noting.

Case 1: the ASP.NET password hasher

Handling user authentication was one of the very first and critical parts of moving from .NET to another platform. ASP.NET Identity stores passwords as Base64-encoded binary blobs. Version 1 uses SHA1-PBKDF2, while Version 2 uses SHA256 or SHA512 with different iteration counts.

If you’re a .NET developer, you probably know the Identity framework well. Since we mostly work with Laravel, we had to dig through Microsoft documentation, Stack Overflow, and the .NET source code to understand the binary formats of ASP.NET Identity V1 and V2 password hashes. It took us several hours of research.

Once we understood the specification, the rest was straightforward. We parsed the header, got the salt, ran PBKDF2 with the right algorithm, and compared the output. There was no guesswork or design choices – just matching the hash to confirm it worked.

Or… it was a different story. We just asked an LLM to do this! It was time-consuming, research-heavy, yet easy to verify. With just a few iterations, we had authentication working and validated it against the existing ASP.NET database!

Case 2: Filament admin dashboard

Filament turns building admin dashboards into just a coding task. You don’t need to make design choices, handle CSS, or coordinate frontend and backend. You describe your tables, forms, and filters in PHP, and Filament creates a polished, consistent admin interface.

This makes Filament a great fit for AI help. The work is repetitive, well-documented, and looks the same across modules. Each resource follows a similar pattern:

  • Define columns
  • Set up form fields
  • Configure filters and actions

Once Claude Code handled one resource, it could generate the rest with only minor changes to each model.

We used Claude Code along with two MCP tools: Laravel Boost MCP, which allowed the AI to interact directly with the app, run Artisan commands, query the database, and inspect the codebase in real time; and Context7 MCP, which provided up-to-date library documentation. This way, Claude Code could see how the app really worked, rather than relying on documentation. When Filament introduced breaking changes, Context7 caught them before we released any faulty code.

We built a full management screen in just one afternoon. It had searchable and sortable tables, inline edit modals, boolean toggle columns, and links between related items. Normally, this would have taken several days.

The pattern

Both examples followed the same pattern: the task was clear, the results were easy to check, and the work involved research or repetition instead of creative problem-solving. That’s where AI helps work best.

Technical details

The auth bridge

We created a custom AspNetPasswordHasher that understands both ASP.NET Identity password formats, parses the binary header, extracts the salt, and uses PBKDF2 to verify the password:

This sits behind a custom AspNetUserProvider registered as a Laravel auth driver. All Laravel surfaces, Filament dashboards, JWT APIs, and future features use the same AspNetUsers table and share password hashes for authentication.

The legacy model adapter

The SQL Server database had over 100 tables. We used Laravel Model Generator to generate Eloquent models from the existing schema, then made minor adjustments and created a base class with common Laravel compliance code. The main component was a base model class that every domain model extends:

The adapter fragment shows some of the mechanisms allowing cross-app usage. The base class checks if a timestamp column is in casts() before using it, since not all tables have CreatedOn or ModifiedBy. It handles all variations smoothly. This design uses existing database timestamps instead of the Laravel native solution. Also, related built-in methods, such as touch(), were updated to work with the new schema. Moreover, the person who created and/or edited the entity is automatically stored in the database, as in the original app. Thanks to this adapter pattern, over 100 SQL Server tables can work seamlessly in a Laravel application.

What we learned

Some tasks fit AI better than others. The password hasher and Filament resources worked well because they involved lots of research or repetition, produced mechanical results, and were easy to check. Unlike open-ended architecture work, these tasks gave Claude Code clear goals and measurable results, which is where AI shines.

Getting good results means following a process, not just giving a prompt. We took small, verifiable steps. The auth bridge went through several rounds of testing, each time comparing known password hashes. In the end, we chose a method that handled both V1 and V2 formats well. Breaking the work into small pieces kept the AI’s output reliable and made it easier to catch mistakes early.

Letting the AI access the real app made a big difference. Laravel Boost MCP let Claude Code inspect the running application, and Context7 MCP gave it the current library documentation. Having both runtime access and up-to-date docs meant fewer made-up methods and less time fixing AI errors.

AI assistance made unfamiliar technology easier to handle. We didn’t need to become ASP.NET experts to connect the auth system, nor did we need to memorise Filament’s API to build the dashboard. AI tools helped us learn new technologies faster, so we could focus on architecture and business logic where our skills mattered most.

The bottom line

Now, the client’s ASP.NET app has a modern admin dashboard and a faster REST API, all built in less time than a full rewrite. The original app still runs, users didn’t notice any changes, and the cloud bill has started to drop. When it’s time to retire the .NET side, the Laravel foundation will be ready.

If you’re dealing with an old codebase and don’t want to rewrite everything, remember: you don’t have to start from scratch. You can build something new alongside it. Share the database, connect the authentication, and migrate at a pace that fits your business. With the right AI tools, the hardest parts get much easier.

Dealing with similar legacy code issues? You don’t have to start from scratch. The THEY.dev team specializes in incremental migrations and AI-assisted development. If you need a hand modernizing your system at a pace that fits your business, let’s talk!