- Client: A healthcare/pharmacy software company
- Industry: Healthcare & Pharmacy Technology
- Services: Legacy System Modernization, AI-Accelerated Software Development
- Outcome: A five-month modernization estimate delivered approximately 40% faster, with a stronger architecture, a reusable component library, and no loss of system knowledge along the way.
Modernizing legacy software often means rebuilding decades of business logic with little documentation, outdated technology, and growing operational risk. Organizations running Delphi applications frequently face shrinking talent pools, increasing maintenance costs, and difficulty integrating with modern platforms.
In this legacy application modernization case study, Keyhole Software migrated a business-critical Delphi application to .NET in roughly three months using AI-assisted software development alongside senior engineering oversight. The project improved maintainability, reduced risk, and created reusable components for future modernization efforts.
Delphi to .NET Modernization at a Glance
- Modernized a decades-old Delphi application by migrating it to a modern .NET C# architecture.
- Beat a five-month delivery target, completing the rewrite in about three months
- Uncovered and fixed a critical risk: non-production environments were pointed directly at live third-party servers
- Extracted a reusable serialization component now available to future modernization projects
- Used LLMs for discovery, documentation, and code conversion, with every architectural decision made by senior engineers
The Challenge
The client’s pharmacy software business relied on a business-critical application written in Delphi, a technology stack most of the original engineering team had long since moved on from. There was no meaningful documentation, no real test coverage, and no one left who fully understood how the system behaved end to end. The source code itself had effectively become the documentation: years of business rules and operational decisions were buried directly in the implementation.
That’s a common starting point for legacy modernization work, but this project had an added wrinkle: a manual review of configuration files revealed that the development and QA environments were pointed directly at production third-party commercial servers. A single misstep during testing could have affected real, live systems.
The mandate was clear: understand a system nobody fully understood anymore, then migrate the legacy Delphi application to .NET while preserving decades of business logic, without breaking anything in the process and without the usual multi-month runway.
The Approach: Understand First, Then Accelerate
The team split the engagement into two connected phases: first making sense of the unknown legacy system, then using that understanding to drive a fast, disciplined rewrite.
Phase 1: AI-assisted discovery.
Before writing a line of .NET, the team fed the Delphi codebase to an LLM with structured prompts and used it to generate Markdown documentation covering entry points, key workflows, and data flows, work that would traditionally take days or weeks of manual tracing compressed into hours. That documentation gave the whole team, and every engineer who touched the project afterward, a shared mental model of a system that had previously lived only in scattered institutional memory.
The team leaned on a simple discipline for using AI responsibly during discovery, built around four questions:
- What should the AI handle versus what requires human judgment?
- How do you communicate with it clearly enough to get useful output?
- How do you evaluate what it hands back?
- How do you validate assumptions safely?
The principles behind this approach are explored in more detail in our companion articles, How We Used LLMs to Understand and Modernize a Legacy Delphi Application and Legacy Delphi to C# Migration Using LLMs, which dive deeper into the frameworks and engineering practices that helped make this project successful.
In this Delphi to .NET migration, AI took on generating documentation, exploring requirements, and iterating on code. Engineers kept ownership of architecture decisions, risk calls, and anything touching the environment. That boundary is what let the team move quickly without losing control of the outcome: the LLM explained what the system did, and engineers decided what still needed to be true about it going forward.
That judgment call paid off directly. Manual review of the AI-generated documentation and the underlying code surfaced the dev/QA-pointed-at-production issue, plus a missing failback mechanism: if a job failed, it failed permanently, with no retry path. Rather than test against live production services, the team built a mock of the third-party commercial service so the legacy Delphi app and the new .NET app could run side by side and be compared safely.
Phase 2: Architecture-led execution.
With the system understood and de-risked, the team moved into the rewrite itself, a three-month effort to hit a five-month deadline. The architecture came first: the team didn’t start converting code until the shape of the new .NET system, including proper abstractions for unit testing, was fully worked out. That upfront planning meant implementation could move directly into execution instead of making structural decisions mid-sprint.
One of the first pieces of work was splitting out the application’s serialization layer into a standalone, reusable NuGet package. It was a well-scoped starting point that also forced early thinking about how the package would be consumed elsewhere.
From there, GitHub Copilot became a genuine accelerator for code conversion. Engineers could hand it a full Delphi workflow (the method, its dependencies, the relevant database queries) and get back equivalent C# along with generated unit tests to validate it.
Technologies Used
- Delphi (Object Pascal)
- .NET
- C#
- GitHub Copilot
- Large Language Models (LLMs)
- NuGet
- Markdown
- Unit Testing
Legacy System Modernization Challenges Discovered During Migration
Understanding the Delphi legacy system didn’t just make the rewrite possible, it surfaced problems the client didn’t know they had. Beyond the production-environment risk and the missing retry logic, the team found a tangle of hardcoded values scattered between config files and code, making the application difficult to deploy consistently across environments. Those values were made fully configurable in the Delphi to .NET rewrite, simplifying future deployments.
Documenting the system also revealed that pieces of its functionality were shared across other applications in the client’s broader portfolio. That was an opportunity the team captured by packaging that logic into a reusable NuGet package that can now be leveraged across future modernization initiatives.
Lessons in Working with LLMs on Legacy Code
Speed came with sharp edges, and the team was candid about where LLM-assisted conversion needed a human backstop:
Context management is everything.
Feeding an LLM legacy code while expecting it to hold a new target architecture in mind at the same time burns through context fast, and in some tooling there’s no visibility into how much you’ve used. The team’s workaround was a set of persistent reference files (an agent brief, a running memory log, and an architecture doc) reloaded at the start of every session and updated at the end of it, giving the AI a consistent knowledge base independent of any single conversation’s context window.
Partial context produces confident wrong answers.
When one sub-method was accidentally left out of a Delphi flow handed to Copilot, the tool didn’t stop to ask what was missing. It inferred a database interface was needed and hallucinated a plausible-looking query against a table structure it invented. It took a developer thirty minutes to untangle. The lesson: verify every dependency is in scope before handing a flow to the model, because a gap won’t necessarily come back as a gap. It may come back as a bug.
Legacy formatting quirks don’t translate safely.
In one section of the original Delphi code, indentation visually implied one branch of conditional logic while the actual End If structure implied another. Copilot, like a human skimming the code, followed the visual structure rather than the true syntax, and the converted C# reproduced the same misread logic.
It took two developers closely comparing the original and converted code to catch it before QA flagged the same issue independently. Inconsistently formatted legacy code needs to be manually verified for intent before it’s handed to an LLM for conversion. The model will read it the way a person skimming it would, not necessarily the way the compiler does.
Results of the Delphi to .NET Modernization
The Delphi to .NET modernization, originally scoped at five months, was delivered in roughly three months, with the discovery phase alone helping compress what would traditionally be weeks of manual system archaeology into hours.
The client came away with more than a ported codebase: a documented, testable .NET application with retry and recovery logic the original system never had, fully configurable deployment settings, and a reusable serialization component available to accelerate the next legacy system on their roadmap. Beyond improving delivery speed, the migration left the client with a codebase that is easier to maintain, test, and extend.
Just as important, the risk that could have caused real damage (non-production environments talking to live production services) was caught and contained before it caused an incident, not after.
Key Takeaways from This Legacy Modernization Project
Across both phases of the Delphi to .NET modernization engagement, the pattern held:
- AI accelerated the parts of the work that were about speed: reading code, drafting documentation, converting syntax, generating tests.
- Engineers retained every decision that required judgment: what the system’s behavior actually meant, what risks it posed, and how the new architecture should be shaped.
Teams that hand an LLM the whole problem tend to get plausible-looking answers that don’t hold up. Teams that use it to move faster on decisions they’ve already made well, as this project did, get results like a five-month migration landing in three.
Planning a legacy application modernization project? Whether you’re migrating from Delphi to .NET, modernizing another legacy technology stack, or exploring how AI can accelerate software modernization, Keyhole Software helps organizations reduce risk, preserve critical business logic, and modernize with confidence.



