← ResourcesMIGRATION Β· SIZING

Sizing Your Target AWS Infrastructure: Matching Resources to Real Workload

Calibrate instances, storage, and bandwidth against your measured workload, neither under nor over-provisioned.

STRALYA15 min readJuly 2026

Why sizing your target AWS infrastructure correctly from the start matters Sizing a cloud infrastructure is very often the invisible factor that tips an AWS migration toward success or toward disappointment. During audits of existing infrastructure, we regularly see two extremes. On one side, teams that migrate with exactly the same resources as their old on-premises system, without accounting for cloud reality: a t3.large instance on AWS is not a dedicated physical server, and it shares network and storage resources. On the other side, teams that over-provision out of fear of the unknown, buy instances that are far too powerful, and end up with an unreasonable AWS bill after six months. Between these two extremes lies a sweet spot defined by your real needs. Correctly sizing your target infrastructure rests on three pillars. First, the exact measurement of your current workload: real CPU consumption (not the theoretical peak, but the average and the 95th percentile), memory used, disk I/O per second, and inbound and outbound network bandwidth. Next, the projection of that workload onto the available AWS offerings, which operate on a very different model from on-premises. Finally, the integration of the business constraints specific to your context: seasonal peaks, projected growth, availability requirements, and the application dependencies you identified upfront. Sizing well also means accepting that sizing is not fixed. AWS offers mechanisms such as auto-scaling, reserved instances, and savings plans that let you adjust as you go. However, this flexibility does not exempt you from starting on a sound footing. An infrastructure that is poorly sized at launch will make cost control harder later, because you will be tempted to compensate for slowness with more resources rather than reworking the design.

Collect current workload metrics to size accurately Sizing a target infrastructure rests first and foremost on reliable figures. You have probably launched an audit of your existing infrastructure to assess the current state: that step was not an end in itself, but the starting point for your sizing. What you need are quantifiable, contextualized measurements. For compute (CPU, memory), you need to know not only the average over a representative period (one or two weeks under normal conditions), but also the 95th percentile under load. The 95th percentile means: over a hundred hours of observation, for ninety-five hours you consumed less than this limit, and for five hours you exceeded it. It is the right compromise between providing headroom and not over-provisioning to handle an abnormal case. Take a concrete example. An application server uses on average 40% of the available CPU on your current infrastructure, but climbs to 85% during request bursts, and to 100% during overnight batch runs. The 95th percentile sits around 65% over the measured period. If you are migrating an instance that physically has 16 vCPU, you must convert this consumption into real vCPU: 16 vCPU x 65% (95th percentile) = 10.4 vCPU. On AWS, you would choose an m5.2xlarge instance (8 vCPU) or a c5.2xlarge instance (8 vCPU) if CPU is the limiting factor, and verify that memory is also sufficient. For storage, measurement covers the total volume occupied today, the growth rate (GB per month), and temporary peaks (for example, before an annual archival). If you have 500 GB in use, with growth of 10 GB per month, and your planning horizon is two years, plan for at least 500 + (24 x 10) = 740 GB, plus a 20% safety margin, so around 900 GB. On AWS, a 1 TB gp3 EBS volume would be appropriate. For network bandwidth, measure your real peaks in Mbps or Gbps of egress (which carries a cost on AWS, unlike ingress, which is free). Finally, for databases, if you have a current RDS instance, extract the number of concurrent connections, the volume of active data (not just disk space), the backup frequency, and the required RTO / RPO (recovery time objective, recovery point objective).

Translate your workloads into AWS offerings and reserve the right size Once you have your metrics in hand, the mapping to AWS instance types comes next. This is where many teams go off the rails, because instance names (t3, m5, c5, r6i, etc.) and their variants (nano, micro, small, medium, large, xlarge, 2xlarge, etc.) form a complex grid that is easy to misread. AWS offers different instance families depending on your workload profile. Instances in the t family (t3, t3a, t4g) are economical and suited to variable workloads, because they use a burst system, where you accumulate CPU credits when load is low and spend them during peaks. If your application has a relatively stable load (the 95th percentile is not too far from the average), a t3.xlarge instance may suffice. The m instances (m5, m6i, m7i) offer a balance between CPU, memory, and network, and are the foundation for many enterprise applications. The c instances (c5, c6i, c7i) are CPU-optimized for intensive compute, data warehousing, or scientific applications. The r instances (r6i, r7i) and x instances (x1, x2) are memory-optimized, essential for in-memory caches (Redis), analytical databases, or search engines. Be careful not to mix the two approaches. Many teams size a t3.large instance assuming that credit burst will save them during peaks, but they quickly discover that burst runs out if peaks are too frequent or too abrupt. If your real 95th-percentile load is 75% CPU sustained, you must buy an instance with enough real CPU for that load, not bet on volatile credits. Generation matters too: an m5 instance is less powerful (per vCPU) than an m6i, which is itself less powerful than an m7i. For disk space, review your projected need (calculated above), round up to a multiple of 100 GB, and ask yourself whether you need special disk performance (IOPS or throughput in Mbps). A standard gp3 (3 IOPS per GB, throughput up to 1 Gbps) is enough for 80% of cases. If you have a database with many small transactions (several thousand per second), consider an io2, which offers up to 500 IOPS per GB. Once the instance type and storage are sized, AWS offers you several purchasing models. On-demand bills you by the actual hour, with no commitment. A reserved instance (1 year or 3 years) cuts the price by 30 to 70%, but requires a commitment and predictability. A savings plan offers a comparable discount with more flexibility (you can change family or region). For a migration, it is common to start on-demand (3 to 6 months) while you assess the real load, then switch to reserved or a savings plan once stabilized. This avoids nasty surprises: reserving an instance that is too large for two years at a reduced price is a costly waste.

Integrate application dependencies and business constraints Your workload in raw figures is only part of the sizing story. You also identified your application dependencies upfront: which application communicates with which other one, how often, and with what data volume. These dependencies influence both the physical placement of resources and their fine-grained sizing. If your business application depends on an RDS database, and that database itself depends on a read replica for reporting, the sizing of the primary database cannot ignore the volume of read requests coming from the application instances. If those instances are over-sized, they will generate more requests than expected, quickly saturating the replica. Conversely, if they are under-sized, they will spend time in queue rather than in compute, and you will see no improvement by increasing database capacity. Another consideration: your availability and latency constraints. If you have an application that requires 99.99% availability (15 minutes of downtime per year), you must provision several instances in redundancy and place them in at least two different AWS availability zones (AZ). This means multiplying capacity by at least 2, and cross-AZ data costs (0.01 USD per GB) are not negligible. If your load is distributed, one smaller instance in each AZ may be more efficient than a single large instance. Seasonal peaks also play a role. Many companies experience predictable peaks (Black Friday, Christmas, back-to-school, fiscal year-end). On AWS, you can enable auto-scaling so that your infrastructure grows and shrinks automatically according to rules you define. But this auto-scaling must be sized to absorb the scaling flow itself. If you go from 5 instances to 20 instances in two minutes (which an abrupt peak demands), the process of starting up, connecting to the database, and filling caches can take 30 seconds per instance. During that time, the existing instances are overloaded. You must therefore plan for a static margin (for example, 15 base instances) and additional auto-scale capacity for peaks. Finally, consider medium-term growth. If your load grows by 20% per year, your initial sizing for a three-year horizon should factor in that growth. Not linearly (provisioning 60% margin from the start would waste costs), but through a planned expansion strategy: start right-sized for day 1, and schedule review points (every 6 or 12 months) to assess whether an upsize is needed.

Validate your sizing before the migration Once you have settled on a theoretical sizing, the temptation is strong to go straight to migration. Do not give in. Several tactics exist to validate your sizing without waiting for migration day. The first is parallel simulation. You provision your sized AWS resources, and for a week or two (under normal conditions, ideally a week that includes a day of higher load), you run a non-critical copy of your application on them, mirroring your current infrastructure. You measure CPU, memory, disk I/O, and network latency under real load. If you observe that the 95th percentile of CPU on AWS regularly exceeds 85%, you are under-sized. If CPU tops out at 20%, you are over-provisioning. This approach requires a few days of preparation (copying data, deploying on AWS, monitoring), but it catches your mistakes before you are in production and before they cost a major regression. The second tactic is load testing. You reproduce your real workload profile (or a representative fraction) with a tool such as JMeter, LoadRunner, or k6, and you run this test against your theoretical sizing. This often reveals bottlenecks that do not appear in passive observation: a database connection pool that is too small, an insufficient cache, or internal network bandwidth that saturates. Finally, if a simulation or load test reveals a problem, you have several levers. First, increase resources (vertical scaling, moving the instance up to a larger type). Next, add more instances (horizontal scaling) and set up a load balancer to distribute the load. Third, optimize the application itself (reduce an algorithm's CPU consumption, cache an expensive database query). Fourth, reduce the actual load (for example, limit the frequency of certain jobs). In most real cases, a combination of these levers (for example, moving from m5.large to m5.xlarge AND adding a Redis cache) is more cost-effective than a pure escalation of resources. The final sizing must take these lessons into account and be documented transparently: what your initial measurement was, what changes you made and why, and what your plan is if the load diverges after the migration.

Adjust sizing after launch and control AWS costs After the migration, your infrastructure is in production, but your sizing work does not stop there. Of course, daily operations (patching, monitoring, alerting) are outside the scope of this page (that is day-to-day managed operations), but adjusting sizing based on real observation of the load IS part of migration planning. The first three months after launch are crucial. You must collect real CPU, memory, disk, and network metrics under actual business conditions, and compare them against your plan. In practice, three scenarios can occur. First, your sizing was accurate, and the observed load matches what you had planned. In that case, you have few changes to make, but you can start to consider reserving instances (1 year or 3 years) to cut the on-demand cost by 30 to 70%. Second, your load is lower than expected. This often happens when an application uses only a small fraction of the data center to itself, or when the migration triggered an unanticipated efficiency gain (for example, your code runs faster on a more modern CPU). In that case, you can reduce the instances to a smaller type. Third, your load is higher than expected. If it is a lasting surprise (not an isolated peak), you must investigate: accidental use of increased performance to launch new processing, additional users, or an error in the initial estimate. You must then move the instances up or add redundancy. Cost can also diverge without the load changing, for other reasons. For example, if you provision too much inbound data coming from another AWS region, you pay 0.02 USD per GB (cross-region cost), which quickly adds up. Or if you leave backup snapshots running too long without archiving them to Glacier (cheaper for cold storage). These optimizations are not sizing in the strict sense, but they follow from it: sizing well also means understanding the structure of AWS costs and ensuring that your architecture honors it. A tool such as AWS Compute Optimizer (which analyzes your load and recommends instance types) or Cost Explorer (which breaks down your bill by service) helps you steer these adjustments. Sizing is therefore never settled once and for all, but a continuous discipline of measurement and adaptation in the first six months after the migration, then an annual or biannual review to account for business growth.

Concrete cases: sizing a web app, a database, and a batch system Let us see how to apply these principles to three realistic profiles you will encounter. Case 1: Web application with many concurrent users. You currently measure 5,000 requests per second on average, 12,000 req/s at the 95th percentile. Each request consumes about 50 ms of CPU. Under load, your server uses 60% CPU, 70% memory (you have 128 GB), and generates 50 Mbps of outbound bandwidth. You project 30% growth over 18 months. On AWS, you size for 12,000 req/s x 1.3 (growth) = 15,600 req/s. If a single m5.2xlarge instance (8 vCPU, 32 GB memory) can handle 2,500 req/s, you need 15,600 / 2,500 = 6.24 instances, rounded up to 7. You deploy 7 behind an application load balancer. For high availability (99.99%), you distribute them: 4 in one AZ, 3 in another. On-demand cost: 7 x USD 0.394/h (m5.2xlarge) x 720h/month = USD 1,981/month. With a 3-year reservation, you would get about USD 600/month, a nice saving. Case 2: Relational database (RDS). You currently have 2 TB of data, with 15,000 transactions per second at peak, and a working set memory (frequently accessed data) of 400 GB. For RDS PostgreSQL, you must choose an instance capable of supporting these transactions and with enough memory to cache the working set. A db.r6i.2xlarge instance (8 vCPU, 64 GB RAM) would be appropriate. You enable multi-AZ for 99.99% (synchronous redundancy, a small delay on commit), and provision 3 TB of gp3 storage (for growth and margin). On-demand cost: USD 2.304/h x 720h = USD 1,659/month, plus USD 0.23 per GB of storage = 3,000 x USD 0.23 = USD 690/month, total USD 2,349/month. With a 3-year reservation, the base would drop to USD 700/month. Case 3: Nightly batch job. You have a large ETL that runs every night for 4 hours, consumes 32 vCPU, 128 GB RAM, and 500 Mbps of network to read from an external source. You have several choices. Create an m5.4xlarge instance (16 vCPU, 64 GB) and let it run 4h/night, or deploy 2x m5.2xlarge in parallel, or use AWS Glue (managed service) or Fargate (containers without infrastructure), which charge you by the hour and by the resource used only. For 4h/night, an m5.4xlarge instance on-demand costs USD 1.504/h x 4h x 30 days = USD 1,803/month. With a light reserved instance (you can share it with other jobs), you would drop to USD 550/month. With Fargate, assuming an average rate of USD 0.04704 per vCPU-hour, 32 vCPU x 4h x 30 days x USD 0.04704 = USD 1,806/month. No major saving in this case, but Fargate spares you the infrastructure management. These three cases show that sizing is not a single calculation, but an adaptation to each component of your architecture, with trade-offs between cost, reliability, and operational simplicity.

Common mistakes to avoid in sizing After working on hundreds of AWS migrations, a few pitfalls come up regularly. First mistake: confusing current consumption with current capacity. You measure that a physical instance uses 30% CPU, and you assume you can use 30% of its capacity on AWS. Wrong. On a dedicated physical server, 30% utilization can mean you still have plenty of headroom before saturation. On AWS, if the 95th percentile climbs to 30%, you are near-optimal. If most of the time you are at 5%, the server is over-provisioned. Context is everything. Second mistake: ignoring load variations. You measure 5 GB/day of storage consumed on average, and you provision 10 GB. But if a cleanup job runs once a month and suddenly consumes 30 GB of temporary space, you run out of room. Always plan a buffer, typically 30 to 50% beyond your worst measurement. Third mistake: applying a naive rule of three. "Our current server has 16 vCPU and handles our load well, so I'll buy an m5.2xlarge (8 vCPU) on AWS." AWS vCPU are not identical to on-premises vCPU, virtualization technologies come into play, and "theoretical" vCPU are not guaranteed to be identical. Base your decision on real benchmarks or a load test, not on a core count. Fourth mistake: neglecting the cost of redundancy. If you need 99.99% availability, you must multiply by at least 2 (two instances or AZs) for certain components. This doubles the base cost. If you size a single "optimal" instance but it fails, you are offline. Two smaller instances are better than one large one. Fifth mistake: forgetting cross-component dependencies. You size your web app correctly, but you forget that each request makes 10 database queries. If you increase the web instances, you also increase the database load, which can become a bottleneck. Validate the whole chain, not just one component. Sixth mistake: assuming that lab validation resembles production. A load test with 1,000 virtual users does not always reproduce the conditions of a real client load with its irregularities, timeouts, and reconnections. Test as close as possible to real traffic, ideally through a period of shadow traffic (a copy of real traffic sent to your new infrastructure without impacting it yet). Seventh mistake: not reassessing after six months. After go-live, the team breathes easier and forgets to check whether the sizing needs adjustment. You end up paying for unused capacity or, worse, suffering from chronic under-sizing hidden by auto-scaling, which masks the problem. Schedule a monthly review for the first three months, then a quarterly one.

AWS TEARDOWN Β· FREE

Get the AWS Teardown: where your bill really goes.

The guide listing the 12 cost areas that leak the most at scale-ups, and how to plug them. Free, by email, no strings attached.