Default Capacity of List
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
When developers ask about the default capacity of List, they are usually talking about C# List<T>, not a generic concept across every language. In .NET, capacity is the size of the internal array backing the list, and it is different from Count, which is the number of elements actually stored.
The Default Capacity in List<T>
For an empty List<T> created with the parameterless constructor, the initial capacity is 0.
That often surprises people who expect an immediate allocation of 4, 8, or 16 slots. In current .NET implementations, the list starts with an empty shared array and allocates storage when the first element is added.
What Happens After the First Add
Once you add the first item, List<T> grows its internal storage. A common observed behavior is that capacity jumps to 4, then grows roughly by doubling as needed.
You will typically see capacity grow like this:
- '
0before any add' - '
4after the first allocation' - '
8' - '
16' - and so on
The exact growth policy is an implementation detail, so you should rely on the fact that capacity grows automatically, not on a specific sequence beyond current runtime behavior.
Capacity Versus Count
This distinction is essential:
- '
Countis how many elements the list currently holds' - '
Capacityis how many elements it can hold before resizing'
A list can have Count = 3 and Capacity = 8. That just means five more elements can be added before another reallocation is needed.
Why Capacity Matters
Resizing a list is not free. When the internal array fills up, the runtime allocates a larger array and copies the existing items into it.
That cost is amortized, which is why Add is still effectively O(1) on average. But if you already know the approximate size of the list, preallocating can reduce copying and improve performance.
This is useful in hot loops, parsers, batch imports, and other allocation-sensitive paths.
Trimming Excess Capacity
If a list temporarily grew large and now holds far fewer elements, you can shrink the backing array.
TrimExcess() is helpful when you want to reduce memory footprint after bulk loading.
When Not to Worry About It
For ordinary application code, the default capacity behavior is usually fine. List<T> is designed to grow efficiently without manual tuning.
Only optimize capacity when:
- profiling shows allocation or copying overhead matters
- the list size is known in advance
- you are constructing many large lists repeatedly
Otherwise, readability matters more than micro-managing internal array growth.
A Small Benchmark Pattern
If you want to evaluate whether preallocation helps in your case, compare both versions under realistic workload.
Then fill them the same way and measure allocations or elapsed time with a profiler or BenchmarkDotNet.
Common Pitfalls
A common mistake is assuming default capacity and default count are the same thing. They are not.
Another mistake is relying on a specific growth sequence as if it were part of the public contract. The important guarantee is automatic growth, not the exact multiplier.
Developers also sometimes preallocate huge capacities everywhere "just in case," which can waste memory instead of saving time.
Summary
- In C#
List<T>, the default capacity of a new empty list is0. - Capacity increases automatically when elements are added.
- '
Countis the number of stored items;Capacityis the size of the backing array.' - Preallocating capacity helps when you know list size ahead of time.
- Treat the exact growth pattern as an implementation detail, not a hard API guarantee.

