Most SharePoint solutions don't fail at launch — they degrade over time as lists grow, jobs multiply, and "just one more flow" piles on. The platform has well-defined limits and protective throttling, and the difference between a solution that scales and one that grinds to a halt is whether you designed for those limits from day one. This is the consultant's field guide to keeping large SharePoint deployments fast and governable.

The 5,000-item list view threshold

The single most misunderstood limit in SharePoint. A list can hold millions of items — up to 30 million — but a single query/view cannot return more than 5,000 items in one request. Exceed it and the operation is throttled with the dreaded "this view cannot be displayed."

The threshold is about the query, not the list size. The fixes:

# Add an index to a column with PnP PowerShell
Set-PnPField -List "Contracts" -Identity "ContractStatus" `
  -Values @{ Indexed = $true }

# Page a large list safely in code (CAML + RowLimit)
<View>
  <Query><Where><Eq>
    <FieldRef Name='ContractStatus' /><Value Type='Text'>Approved</Value>
  </Eq></Where></Query>
  <RowLimit>2000</RowLimit>
</View>
Index before the list gets big. SharePoint won't let you add an index to a column once the list already exceeds the threshold (the indexing operation itself would breach the limit). Plan indexes when you design the list, or add them while the list is still small.

Throttling: the 429 you must respect

SharePoint Online protects shared capacity by throttling apps that send too many requests too fast. You'll get HTTP 429 (Too Many Requests) or sometimes 503, with a Retry-After header telling you how many seconds to wait. The only correct response is to back off:

HttpResponseMessage resp = await httpClient.SendAsync(request);
if ((int)resp.StatusCode == 429 || (int)resp.StatusCode == 503)
{
    var retry = resp.Headers.RetryAfter?.Delta ?? TimeSpan.FromSeconds(10);
    await Task.Delay(retry);
    // retry the request (with a capped exponential back-off)
}
Retrying immediately through a 429 makes it worse — SharePoint escalates throttling and can temporarily block the whole app. Honour Retry-After exactly, add exponential back-off with jitter, and reduce concurrency. Decorate requests so Microsoft can identify well-behaved traffic (below).

Decorate your traffic with a User-Agent

Microsoft asks apps to identify themselves with a structured User-Agent string (ISV|CompanyName|AppName/Version or NONISV|...). Decorated traffic is throttled more leniently and is far easier to diagnose. PnP libraries set this for you; for raw HTTP, set it yourself:

request.Headers.UserAgent.ParseAdd("NONISV|Contoso|ContractSync/1.4");

Other limits worth designing around

Governance: keeping it healthy over time

Performance is half the story; governance keeps the environment from sprawling into chaos. A practical checklist:

Treat governance as code where you can: provision sites from templates, set indexes during provisioning, and audit permissions with PnP PowerShell on a schedule. The environments that stay healthy are the ones where the right configuration is applied automatically, not left to whoever clicked "create site."

A simple maturity test

Ask three questions of any SharePoint solution heading to production:

  1. Will every list view still return under 5,000 rows when this list is ten times bigger — and are the filter/sort columns indexed?
  2. Does every piece of code that calls SharePoint honour Retry-After, decorate its User-Agent, and batch where possible?
  3. Is the site provisioned from a standard template, with lifecycle, permission, and sharing policies defined?

If the answer to all three is yes, the solution will scale and stay governable. If not, you've just found your backlog. Designing for limits and governance isn't glamorous, but it's exactly what separates a SharePoint deployment that thrives for years from one that quietly becomes everyone's least favourite system.

DS

Dhaval Shah

Cloud Solution Architect — 18+ years across SharePoint, Microsoft 365, and Azure AI.