Private vs public cloud once the application is in production
Four properties of the application decide the question, and each one can be checked from your own AWS or Azure account before any vendor call. We run a managed private cloud on our own hardware, in one U.S. data center. For some applications the right answer is to stay on AWS or Azure.
What the NIST definition leaves open
NIST SP 800-145, published in September 2011, lets a private cloud be owned, managed and operated by the organization using it, a third party or some combination of them, on or off premises. A public cloud is provisioned for open use by the general public and sits on the provider's premises. What separates the options for a running application is who owns the hardware and whose engineers operate it. Who patches the guest operating system, and who restores last Tuesday's database, gets decided in the contract.
Product names blur the line. An EC2 Dedicated Host is a physical server dedicated to one customer inside a public cloud, built for placement control and for licenses counted per socket or per core, such as Windows Server and SQL Server.
For any proposal, including the arrangement you run today, get three answers in writing: the owner of the hardware, the people with administrator access to the hypervisor, and the person who takes the ticket when the database needs work. On our cloud, we own the hardware and our engineers run it.
Managed services with no direct replacement
Portability comes down to what the application calls, and two lists show it. Start with the bill, grouped by service:
aws ce get-cost-and-usage --time-period Start=2026-06-01,End=2026-09-01 --granularity MONTHLY --metrics UnblendedCost --group-by Type=DIMENSION,Key=SERVICE
Then search the code. In a Node project, this lists every AWS SDK v3 client declared in the project's package.json files:
grep -rhoE '"@aws-sdk/client-[a-z0-9-]+"' --include=package.json --exclude-dir=node_modules . | sort -u
Python projects call boto3.client( and boto3.resource(, so search for both. On Azure, az resource list --query "[].type" -o tsv | sort | uniq -c counts the resource types in the current subscription. Read every line of the bill and of the code search. A queue that costs $4 a month can be the service the whole order flow runs through.
Containers move well when the manifests stay generic. The pieces to look for on EKS are load balancer annotations such as service.beta.kubernetes.io/aws-load-balancer-type, storage classes backed by the EBS CSI driver, and pod permissions granted through IAM roles for service accounts or EKS Pod Identity, which runs only on EKS. Each needs a substitute before the same Helm chart runs on another cluster. We helped one software customer take its product off a packaged Kubernetes distribution and onto native Kubernetes, and supplied the test environments and the resource consumption testing along the way.
Sort each service into one of the three groups in the table. A product built mostly on the third group should stay where it is. DynamoDB local runs on a laptop for development and testing, and production still needs DynamoDB.
| Group | Examples | What leaving involves |
|---|---|---|
| Runs anywhere | EC2 and Azure VMs, block storage, containers, and the PostgreSQL, MySQL and SQL Server engines | Rebuild the servers and restore the data. The managed features around a database, such as automated snapshots and IAM database authentication, need a substitute |
| Replaceable at an operating cost | S3 or Blob Storage, Redis caches, SQS or Service Bus queues | An S3 compatible object store, Redis or RabbitMQ, plus someone to patch and monitor it for as long as it runs |
| No direct replacement | DynamoDB, Lambda flows wired through EventBridge and Step Functions, Cognito user pools, Cosmos DB, Durable Functions | Rewriting the parts of the product that use them |
When the installer wants sysadmin
We built this cloud to run software that was never designed for a cloud, and companies bring us legacy applications that ran poorly after landing on AWS or Azure. For Windows and SQL Server applications, look at the managed database service first.
On RDS for SQL Server, the master user gets the processadmin and setupadmin server roles, without sysadmin. RDS does not support xp_cmdshell, maintenance plans, FILESTREAM, triggers at the server level, or the TRUSTWORTHY database property, which needs sysadmin. An installer that demands sysadmin, or a vendor script that shells out through xp_cmdshell, stops there.
A managed database also sets the upgrade calendar. RDS ended support for SQL Server 2016 on July 14, 2026 and is scheduling every remaining 2016 instance for an upgrade to SQL Server 2019. Once a mandatory upgrade passes its apply date, RDS can run it outside the maintenance window you chose. Azure SQL Managed Instance runs the latest engine under its Always-up-to-date update policy, or the SQL Server 2022 or 2025 engine under the policy named for that version. A database there can run at compatibility levels back to SQL Server 2008, but a vendor's support matrix lists engine versions, and the compatibility level leaves the engine unchanged. On a managed instance, SELECT @@VERSION returns 12.0.2000.8 whatever engine sits underneath, which can trip an installer that parses the string.
Microsoft's extended support for SQL Server 2016 ended the same day, and Windows Server 2016 follows on January 12, 2027. An application whose vendor certifies nothing newer than 2016 needs a server where someone controls the version: a VM on EC2 or Azure that your team operates, or a host that operates it for you.
We host older business software that its owners have chosen to keep, such as accounting and timekeeping applications reached from several offices. After a migration, our engineers keep tuning the environment around the application until it runs the way your team expects, without changing how the application was built.
Since October 1, 2019, Microsoft's terms bar on premises licenses bought without Software Assurance and mobility rights from the dedicated hosted services of its Listed Providers: Alibaba, Amazon, Google and Microsoft. The Flexible Virtualization Benefit, introduced in October 2022, lets licenses with Software Assurance or a subscription run on an outsourcer's shared servers, and it excludes the same four. Check your agreement before assuming the licenses travel with the application.
CPU credits and gp2 burst balance
Before blaming another tenant for a slow EC2 database, check the limits built into the instance and volume types. Two of them slow a server down in a way that looks like a neighbor.
T3 instances launch in unlimited mode by default, so a busy t3.medium keeps its CPU and the extra usage shows up on the bill at a flat rate per vCPU hour. In standard mode, the same instance drops back to its baseline of 20 percent per vCPU once CPUCreditBalance runs out.
Storage has its own bucket. A 100 GiB gp2 volume has a baseline of 300 IOPS and can burst to 3,000 IOPS for about 33 minutes on a full credit balance. After that, the database runs at 300 IOPS until BurstBalance refills, which takes five hours from empty. When a database on gp2 slows after a busy stretch and recovers hours later, graph BurstBalance first. A gp3 volume holds a baseline of 3,000 IOPS and 125 MiB/s at any size, with no burst bucket to drain.
Who takes the database ticket?
On RDS, AWS takes over patching and the backup mechanics, and the database's behavior stays with your team. A restore shows where that line sits. The restored instance comes up under a new name and endpoint. Its volumes keep loading blocks from S3 in the background, so queries can run slow for a while. On SQL Server, each database is restored to within one second of the others, so a transaction that spans two databases can come back inconsistent. Someone on your side repoints the application and checks the data.
For the same engine on EC2 and on RDS, the work divides like this:
| Task | SQL Server or PostgreSQL on EC2 | The same engine on RDS |
|---|---|---|
| Guest OS and engine patches | Your team | AWS, in a weekly 30 minute window you choose. Optional updates wait for your team, and mandatory ones apply after their date |
| Backups | Your team, with EBS snapshots, AWS Backup or native backups | AWS, automated, kept for the retention period you set |
| Restore to a point in time | Your team | Your team starts it, and RDS builds a new instance with a new endpoint |
| Query tuning, indexes and schema | Your team | Still your team |
Egress at $0.09 per GB on a split deployment
Moving QA while production stays on AWS adds a recurring data transfer line, sized by what you copy. Internet egress from US East (N. Virginia) costs $0.09 per GB for the first 10 TB a month, after a free 100 GB a month shared across all services and Regions. A SaaS product with paying customers usually spends that allowance on its own traffic, so count copies from the first gigabyte.
Copying a 150 GB compressed database backup out once a week comes to about 650 GB a month (150 × 52 ÷ 12), roughly $59. The same copy every night is about 4,560 GB and $411. A fixed test dataset avoids the recurring copy. Our provisioning sequence ends by loading the base users and the dataset your team chose, so that dataset crosses the network once.
AWS and Azure waive egress for customers who leave, and each requires a full exit. Azure credits egress for up to 60 days from a transfer start date you give Azure Support, and only after you cancel every subscription on the account. AWS requires moving all of your data off AWS within 90 days, approved through a support case, and does not require closing the account. A company that keeps production on AWS pays the standard rate on every copy.
Five cases for AWS or Azure
- Serving from more than one region. Our cloud runs in one U.S. data center, so a product that serves Europe and the US from local regions, or has to survive losing a region, belongs on AWS or Azure.
- A product built mostly on services with no direct replacement, such as DynamoDB or Cognito user pools.
- Load that swings tenfold within a day, where paying by the second for capacity that exists only at the peak costs less than owning it.
- Platform teams that already run the account well and want direct control of every setting. A managed provider adds little for them.
- AI workloads at very high volume. We are too small for them.
Start with the QA stack
We usually start a new customer on QA and leave production where it is. QA is often the least developed stack a team has, and it turns over faster than development, because each validation or regression run needs a fresh copy with a known dataset.
One customer's QA stacks pair an application server with a SQL server, reachable from outside so testers can open the application in a browser and run it in test mode. The customer's QA lead approves a saved environment configuration for each stack type, and we build from it in order: operating systems, installed software, environment configuration, the application, then the base users and dataset. That customer started with QA servers, proved them out and then added development servers. The same company still employs a person whose only job is reviewing its AWS invoice, and the effort of reading that invoice was one reason it began hosting dev and QA with us.
Moving QA first shows whether the application installs and passes its tests on the new stack, and how our engineers handle your requests. Performance under live traffic and a restore at production size stay untested until the production plan. For that plan, we design the target environment, present it, and test the cutover repeatedly with your developers. If you want to hand us production on day one, we will slow that down until we know you and the application.
Bring the workload you would move first to a call with a consultant.