Know your Business Central limit, play within it!

In the cloud, we must play by Microsoft rules, but what are the rules and limits? In this video, I take a look at the current limits and what look at the impact of current projects. Check it out:

https://youtu.be/JkwA6zCy5RU

In this video, Erik walks through one of the most important reference pages for Business Central cloud developers and administrators: the Operational Limits for Business Central Online documentation on learn.microsoft.com. This page defines the playing field — the hard limits Microsoft has set for how the cloud service is configured. If you’re on-premises, you can configure your server however you like, but in the cloud, these limits apply to everyone.

Why This Page Matters

With Business Central in the cloud and Microsoft controlling the environments, there are restrictions and limitations designed to keep things running smoothly — to prevent anyone from “blowing up the cloud.” Erik notes that he frequently returns to this single documentation page to answer all sorts of questions about what’s possible and what isn’t. Understanding these limits is essential for developers, consultants, and administrators working with BC online.

Client Connection Limits

The first section covers client connection limits. One notable setting is the 10-minute reconnect period — the time during which a client can reconnect to the service after being disconnected. Erik admits he’s not entirely sure of the real-life impact of this one, since in most cases you’re forced through a new session anyway. There may be a difference in behavior depending on whether you reconnect within or after that 10-minute window.

Data Handling Limits

The data handling section contains several limits worth knowing:

  • Max items in OData/Graph serialization: 10,000 objects for serialization and deserialization. If you’re connecting to Microsoft Graph, this could have an impact.
  • Maximum upload/download size: 350 MB. This applies to everything — PDF reports, configuration packages, file uploads. If you’re producing a massive PDF report of all your value entries, it cannot exceed 350 MB.
  • Stream read size: Limited to 1 MB at a time. If you upload a 350 MB file, you cannot read the entire thing into memory at once. You must perform multiple reads and write the data incrementally. The ReadText or Read methods on streams will return partial data, and you simply keep reading until done.

Database Limits

These are essentially various timeout settings:

  • Search timeout: 10 seconds. You may have encountered this when using the multi-column search function in a list page with many columns — if the search can’t complete in 10 seconds, it times out.
  • SQL command timeout: 30 minutes. Any SQL command running longer than this is terminated.
  • SQL connection idle timeout: Unlikely to affect AL development directly — this is about how Microsoft’s infrastructure connects to the database.
  • Connection timeout: 1.5 minutes to wait for the server to connect to the database. Again, more of an infrastructure concern.
  • Long running SQL query threshold: 1 second. This doesn’t kill your query — it simply generates telemetry when a SQL command runs longer than one second. You can use this data to identify and optimize slow operations.

Asynchronous Task Limits

This is the section Erik says he runs into most often. These limits govern background sessions, scheduled tasks, and page background tasks.

Background Sessions (StartSession)

  • Maximum runtime: 8 hours. After that, the session is killed. This can be problematic for long-running operations like cost adjustments or large data replication jobs — you need to design your processes to complete within this window.
  • Maximum concurrent background sessions: 10. You can queue up to 100 (by calling StartSession 100 times), but only 10 will actually execute simultaneously. The rest wait for a slot to open.
  • Child session max concurrency: 5 per parent session. If a session spawns child sessions, no more than 5 can run concurrently from the same parent.
  • Maximum queued child sessions: 100 waiting to start.

Scheduled Tasks (Job Queue)

There’s an important distinction between background sessions and scheduled tasks. Background sessions are started with StartSession. Scheduled tasks are started via the task scheduler, which is what powers the job queue.

Maximum concurrent scheduled tasks: 3. This is a critical limit. If you have many job queue entries — especially across multiple companies — you can easily exhaust these three slots. Various system tasks like updating headlines, telemetry, and license checks constantly consume scheduled task slots, even if they only run for a fraction of a second.

Erik shares a practical workaround: from a scheduled task, you can start a background session. This way, the scheduled task itself completes quickly (freeing one of the 3 slots), while the actual work runs in a background session (tapping into the pool of 10). This is a useful technique for customers with many companies where job queue entries are getting backed up.

Session Recursion and Page Background Tasks

  • Maximum session recursion depth: 14. A session starting a session starting a session, and so on. Erik has never hit this limit, but it exists to prevent infinite loops of sessions restarting themselves.
  • Page background task default timeout: 2 minutes. Erik uses page background tasks in his SharePoint connector app — when you navigate to a record, a page background task queries SharePoint for related files and updates the FactBox without blocking the UI. You have 2 minutes for this to complete.
  • Page background task max timeout: Can be specified via a parameter, up to the documented maximum.

Report Limits

  • Maximum documents in Word layout merge: Default 200, maximum 500. Users can override this per report from the request page. If exceeded, the report is canceled.
  • Report execution timeout: Default 6 hours, maximum 12 hours. Note this is different from the 8-hour limit for background sessions.
  • Maximum dataset rows: Default 500,000, maximum 1,000,000 records.

Query Limits

  • Query timeout: 30 minutes.
  • Maximum records: 1,000,000.

Company Limits

A newer and much-discussed limit: maximum 300 companies per environment. Erik explains that the primary reason for this is the upgrade process. Each company has a full set of tables, and upgrades must process all companies in a single massive SQL transaction. With 300 companies multiplied by thousands of tables, that’s already an enormous transaction. If you need more than 300 companies, you need to run multiple environments.

OData Limits

OData has its own set of important limits:

  • Body size: 350 MB (same as general upload/download).
  • Maximum concurrent requests: 5. Additional requests queue up. If the queue exceeds 100 pending requests, you get a 503 (Service Temporarily Unavailable). While waiting in the queue, you may receive a 429 (Too Many Requests).
  • Maximum entities per request: 20,000. This is a common gotcha — if you need 21,000 records, you’ll get the first 20,000 and must use the skip token to fetch the next page. Tools like the Power BI connector handle this automatically, but if you’re making raw HTTP calls, pagination is your responsibility.
  • Batch operation limit: 100 operations per batch command.
  • Maximum pending requests: 95 (plus the 5 executing, totaling 100).

OData Rate Limits

This is another area that frequently causes issues:

  • Sandbox: 300 requests per minute
  • Production: 600 requests per minute

These limits are per environment, not per user or per company. A 4-user Business Central environment gets the same 600 requests per minute as a 500-user environment. Erik strongly feels these should scale based on number of users or companies. He’s seen real-world customers with many users, active websites, and integrations hitting these limits regularly.

OData Timeout and Webhook Limits

  • OData request timeout: 8 minutes. Your API page needs to return its 20,000 records within this window.
  • Maximum webhook subscriptions: 200 per environment. Since webhooks are per-company, this becomes a significant constraint in multi-company scenarios. With 300 companies, you can’t even have one webhook per company. Erik recounts having to implement creative workarounds — creating a shared webhook table across companies and routing triggers through it instead of using proper per-company webhooks. He believes this limit should scale differently rather than being a hard cap of 200.

SOAP Limits

SOAP limits are largely similar to OData, with one notable exception: the body size is limited to 65 MB compared to 350 MB for OData.

The Documentation is Open Source

Erik highlights something many people may not realize: all Business Central documentation is open source and lives on GitHub, in the dynamics365smb-devitpro-pb repository. You can browse to the specific file for operational limits, and more importantly, you can view its full commit history.

This means you can track exactly when limits change. For example, Erik shows that the webhook subscription limit was changed in March 2022 — a change that impacted a project he had started earlier when the limit was different. He makes it a habit to check this file after each release to see if any limits have been modified.

Even better, because it’s open source, you can submit pull requests to improve the documentation. If Microsoft likes your contribution, it gets merged into the official docs.

Bonus: The UpperLimit Function in AL

While the video focuses on operational limits, Erik also provides a code example that demonstrates the upperlimit function in AL — a useful FlowField technique for calculating balances up to a filtered date:

tableextension 66100 "My COA" extends "G/L Account"
{
    fields
    {
        field(66100; MyBalance; Decimal)
        {
            FieldClass = FlowField;
            CalcFormula = sum("G/L Entry".Amount where("G/L Account No." = field("No."),
                                                       "Posting Date" = field(upperlimit("Date Filter"))));
        }
    }
}

pageextension 66100 "My COA Page" extends "Chart of Accounts"
{
    layout
    {
        addafter("Net Change")
        {
            field(MyBalance; Rec.MyBalance)
            {
                ApplicationArea = all;
            }
        }
    }
}

The upperlimit function used within the CalcFormula takes the “Date Filter” and uses only its upper bound. This means if a user sets a date filter like 01/01/2023..03/31/2023, the FlowField will sum all G/L Entry amounts where the posting date is less than or equal to March 31, 2023 — effectively calculating a running balance up to that date rather than just the net change within the filtered range.

Summary

The Operational Limits page is essential reading for anyone working with Business Central online. Here are the key takeaways:

  1. Know the limits before you design. Whether it’s the 8-hour background session cap, the 3 concurrent scheduled tasks, or the 600 OData requests per minute, these constraints should inform your architecture from the start.
  2. Use workarounds wisely. Techniques like starting background sessions from scheduled tasks can help you work within the constraints.
  3. Watch for changes. Since the documentation is on GitHub, you can track when limits change and plan accordingly.
  4. Some limits don’t scale with your environment size — OData rate limits and webhook subscriptions are per-environment regardless of user count, which can be painful for larger implementations.
  5. Contribute back. The documentation is open source — if you find something that needs improving, submit a pull request.