🍱 Lunchbox Hands

testing

Sample File Sizes for Testing: 1 MB, 10 MB, 100 MB and Why They Matter

A practical guide to which file sizes you should actually test, the real-world thresholds they map to (form uploads, API gateways, CDN edge limits), the decimal MB vs binary MiB gotcha that causes off-by-5% limit bugs, and why round numbers are the worst test inputs you can pick.

Ask a developer which file sizes they test uploads with and you’ll usually hear “one megabyte, ten megabytes, a hundred megabytes.” Those are fine starting points but they’re not the hard work. The hard work is knowing why those sizes exist, what real limits they’re probing, and why the exact byte count often matters more than the order of magnitude. This guide covers all three.

The limits that actually matter in production

File size constraints come from half a dozen different layers in a typical web stack. Each one has a different default limit — and they often don’t agree with each other.

Form fields and avatar uploads (100 KB – 500 KB) are typically limited by your application server or a multipart/form-data parser. Libraries like busboy, multer, and formidable all have their own defaults. A 100 KB ceiling is common for profile photos; 500 KB for general user-submitted images. Above that, you’re usually compressing client-side or redirecting to signed storage.

Email attachments (10 MB – 25 MB) are gated by SMTP servers, not your app. Gmail’s inbound limit is 25 MB per message (combined). Exchange defaults vary but 10 MB per attachment is a common corporate policy. If you’re generating or processing attachments, test both sides of those numbers.

API gateway body limits (1 MB – 10 MB) are the silent killer. AWS API Gateway has a hard 10 MB payload limit for REST APIs and 128 KB for WebSocket frames. Cloudflare Workers allows up to 100 MB per request body. Vercel’s edge functions cap at 4.5 MB. These limits exist independently of your application code and produce terse 413 Content Too Large errors that are easy to misattribute.

CDN and object-storage stress (50 MB – 250 MB) tests chunked upload behavior, multipart assembly, and timeout windows rather than hard block limits. Most storage providers (S3, GCS, R2) don’t impose a practical per-file maximum beyond their multipart upload size rules, but your signed-URL expiry and network layer timeouts will.

Quick reference: common test sizes and what they probe

SizeDecimal bytesWhat it tests
100 KB100,000 BAvatar / profile photo upload limits
500 KB500,000 BRich-text editor attachment limits
1 MB1,000,000 BBaseline payload; typical “small file” code path
4.5 MB4,500,000 BVercel / Next.js edge function body limit
5 MB5,000,000 BCommon S3 multipart threshold (below = single PUT)
10 MB10,000,000 BAWS API Gateway REST hard cap; corporate email
25 MB25,000,000 BGmail inbound attachment ceiling
50 MB50,000,000 BCDN edge timeout stress; browser memory pressure
100 MB100,000,000 BCloudflare Worker body limit; chunked upload testing

Test the boundary, not the middle

If your limit is 10 MB, a 5 MB test file proves almost nothing. The failure mode is at the edge — specifically at limit - 1 byte and limit + 1 byte.

A 9,999,999-byte file must succeed. A 10,000,001-byte file must fail with the correct status code and a useful error message (not a 500, not a timeout, not a cryptic network error). If both of those pass, you’ve covered the boundary. A single 5 MB file in the middle proves the happy path works; it tells you nothing about whether your limit logic is correct.

This sounds obvious, but boundary testing is routinely skipped in favor of “reasonable” inputs. Production outages happen at the edge, not in the middle of the valid range.

The MB vs MiB trap that causes off-by-5% limit bugs

This is where a lot of real bugs originate. “Megabyte” is ambiguous in computing:

  • 1 MB (megabyte, decimal) = 1,000,000 bytes — used by storage vendors, network engineers, and most modern tools.
  • 1 MiB (mebibyte, binary) = 1,048,576 bytes — used by operating systems reporting RAM and disk usage, and by some server configs.

The gap is 4.86% — close enough to be invisible in casual use, severe enough to produce a mismatch between a documented limit and real behavior.

Here’s a concrete failure scenario: your server config says client_max_body_size 10m (nginx syntax, binary mebibytes). That’s 10,485,760 bytes. Your frontend tells users the limit is “10 MB” and enforces it client-side at 10,000,000 bytes. Those two checks diverge by 485,760 bytes. Users sending files between 10.0 MB and 10.49 MB pass your client-side guard, then hit a 413 from nginx. Support ticket: “I uploaded a 10 MB file and got an error.”

The fix is to work in the same unit throughout: check the actual byte limit in your config, enforce that exact number in bytes on the client, and use a Bytes / Filesize Converter when translating between the values you read in a config and the numbers you put in code.

Why round numbers are the wrong test inputs

A round number like 1,000,000 rarely lands on the interesting boundary. Real limits tend to be round in their native units, which usually aren’t decimal megabytes:

  • S3’s minimum multipart upload part size is 5 MiB = 5,242,880 bytes, not 5,000,000.
  • Cloudflare Workers’ 100 MB body limit is documented in decimal, but nginx configs are often in binary, so a 100 MB file is not guaranteed to hit both limits the same way.
  • Browser FileReader and the File API report sizes in bytes, so if your code reads file.size > 10_000_000 and your server rejects at 10 * 1024 * 1024, they disagree by half a megabyte.

Test files should hit the exact byte count that matches the limit you’re probing — not the nearest round megabyte.

Generating exact-size test files

Most approaches for creating test files produce approximate sizes. dd if=/dev/zero bs=1M count=10 gives you binary megabytes, not decimal ones. Truncating a file to size gives you sparse bytes that may not stress actual I/O paths. Downloading arbitrary files from the internet introduces unknown content that may not match the format your code expects (a parser that accepts only valid ZIP files won’t be fooled by a renamed block of zeros).

The Sample File Generator produces real, valid files — JPEG, PNG, PDF, ZIP, CSV, JSON, and 16 other formats — at any exact byte target up to 250 MB. It uses decimal units (1 MB = 1,000,000 bytes exactly) and runs entirely in your browser, so nothing is uploaded to a server. Pick your format, enter 9999999 or 10000001, and download a file that actually exercises the right code path.

For translating between the units you see in config files and the byte counts you need in code, the Bytes / Filesize Converter handles both decimal (MB) and binary (MiB) conversions — useful for turning a nginx client_max_body_size 10m into the 10485760 you should be checking against in your client-side guard.

The combination — an exact byte count in a real file format — is what makes a file size test actually mean something.