I have migrated several legacy .NET applications to AWS Elastic Beanstalk over the years — some from on-premise Windows servers, some from shared hosting, and some from other cloud providers. The technical steps are well-documented. What is less documented is the operational discipline required to do it without any downtime and without your users noticing.

This is the playbook I follow.

Why Elastic Beanstalk for .NET

Elastic Beanstalk is AWS's managed platform for deploying applications without managing the underlying EC2 infrastructure directly. For .NET applications, it supports both Windows Server environments (for older .NET Framework apps) and Linux environments (for .NET Core and .NET 5+). You get auto-scaling, load balancing, health monitoring, and rolling deployment capabilities out of the box.

For a legacy .NET app that needs to move to the cloud without a full rewrite, it is often the right starting point — lower operational overhead than bare EC2, more control than Lambda, and a migration path that does not require containerization upfront.

Phase 1: Prepare Before You Touch AWS

The migration begins before you create a single AWS resource. There are three things I always do first.

Externalize all configuration. Legacy .NET apps often have database connection strings, API keys, and environment-specific settings hardcoded in Web.config or appsettings.json committed to the repository. Before the migration, I move every environment-specific value to AWS Systems Manager Parameter Store or Elastic Beanstalk environment variables. The application code reads from environment variables; secrets never live in source control.

Audit session state. If your application uses in-process session state (the ASP.NET default), it will break the moment you have more than one instance behind a load balancer. I replace in-process session with a distributed session provider backed by Redis (ElastiCache) before the migration. This is also what enables zero-downtime deployments — when Elastic Beanstalk spins up a new instance during a rolling deploy, the new instance can access all existing sessions immediately.

Run the app locally against production-equivalent config. I set up a local environment that mirrors the target AWS configuration as closely as possible and run the full application against it before the migration day. Surprises that surface in this phase are far cheaper to fix than surprises that surface during a live cutover.

Phase 2: Build the AWS Environment in Parallel

I never decommission the old environment before the new one is proven. I build the Elastic Beanstalk environment completely — application tier, RDS database (if migrating from a local database), ElastiCache, and all supporting infrastructure — and run it in parallel with the existing system.

Database migration strategy. If you are migrating the database as well, use AWS Database Migration Service for the initial bulk load, then enable ongoing replication. This keeps the new database in sync with the old one during the parallel-run period. You can verify data integrity without any risk to production.

DNS TTL reduction. At least 48 hours before the cutover, I reduce the TTL on the DNS record pointing to the application from whatever it currently is to 60 seconds. This means that when I make the DNS change during the cutover, it propagates to most clients within a minute rather than hours.

Phase 3: The Cutover

This is the part that makes people nervous. Here is exactly how I approach it.

I schedule the cutover for the lowest-traffic period of the week — typically early Sunday morning. I have monitoring active on both environments. I have a rollback plan documented and rehearsed.

The sequence:

  1. Put the old system in read-only mode (or display a brief maintenance notice for truly stateful operations)
  2. Run a final database sync to confirm zero data drift
  3. Update the DNS record to point to the Elastic Beanstalk load balancer
  4. Monitor incoming traffic on the new environment for 15 minutes
  5. Verify key user flows manually
  6. Remove the read-only mode

With a 60-second DNS TTL and a prepared ElastiCache session store, most users experience nothing. The ones who were mid-session are served a new session on the new environment — the session data is in Redis, so they do not even need to log in again.

The connection string moment. This is the step where most teams have problems. Connection strings in Elastic Beanstalk are injected as environment variables. In .NET Core this is straightforward — the configuration system reads from environment variables by default and they override appsettings.json. For legacy .NET Framework apps on Windows Server environments, you need to map environment variables to the Web.config using configuration transforms. I always test this mapping explicitly in staging before touching production.

Phase 4: Post-Migration Validation

I keep the old environment running for at least two weeks after a successful migration. Storage and compute costs for an idle environment are minimal, and having the ability to roll back is worth every cent.

During the validation period I monitor: error rates, response time percentiles, database query performance, and any logged exceptions that did not exist before the migration. The profile is almost always cleaner on Elastic Beanstalk than on the old environment — managed patching, auto-scaling, and proper infrastructure tend to resolve a number of intermittent issues that had been attributed to the application.

If you are planning a .NET cloud migration and want to talk through the specifics of your architecture, get in touch. Every legacy system has its own character, and the details matter.