# Performance Best Practices

> Measured ways to speed up TX Text Control: the Core engine, Selection objects, the internal format, a late PDF, short requests and measuring your own workload.

- **Product:** TX Text Control .NET Server
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET Server > Performance and Scalability > Performance Best Practices
- **2512 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/best-practices/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/best-practices/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/best-practices/llms-full.txt

---

Several decisions make document processing with TX Text Control .NET Server measurably faster, and Text Control has published benchmarks for most of them. Each recommendation comes with its numbers and the conditions they were measured under, so that you can judge which ones matter for your documents, and with a link to the page that shows the code. The last one matters most: measure with your own templates and data.

### At a Glance

| Practice | Effect | Read |
|---|---|---|
| Use the Core engine | PDF from plain text up to 11 times faster than with the Classic engine | [Use the Core Engine](#use-the-core-engine) |
| Build text with Selection objects | About twice as fast as inserting, selecting and formatting | [Build Text With Selection Objects](#build-text-with-selection-objects) |
| Keep documents in the TX Text Control format while they change | No conversion when loading and saving | [Keep the Internal Format Until the End](#keep-the-internal-format-until-the-end) |
| Return short jobs, queue long ones | A typical invoice in about 300 ms | [Keep Requests Short](#keep-requests-short) |
| Keep processing apart from editing | Editing sessions stay responsive under load | [Separate Processing From Editing](#separate-processing-from-editing) |
| Use processes for large batches | 100 merges about three times faster in parallel processes | [Multiple Processes](https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/multiple-processes/llms-full.txt) |
| Compress images in PDF documents | 14.68 MB down to 1.48 MB in a test document | [Keep Documents Small](https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/large-documents/#keep-documents-small) |
| Measure your own workload | Every benchmark depends on its documents and hardware | [Measure Your Own Workload](#measure-your-own-workload) |

### Use the Core Engine

The Core engine, `TXTextControl.TextControl.Core.SDK`, was faster than the Classic engine in both of Text Control's published comparisons. In the first, a text with one GUID per line was loaded into `ServerTextControl` and saved as DOCX and PDF:

| Lines | Core, DOCX | Core, PDF | Classic, DOCX | Classic, PDF |
|---|---|---|---|---|
| 100 | 11 ms | 23 ms | 51 ms | 214 ms |
| 5,000 | 113 ms | 684 ms | 289 ms | 7,842 ms |
| 100,000 (1,588 pages) | 3,047 ms | 14,518 ms | 5,885 ms | 159,313 ms |

A second benchmark compared individual operations, averaged over five runs:

| Operation | Classic on Windows | Core on Windows | Core on Linux |
|---|---|---|---|
| A table with 500 rows and 10 columns, filled with text | 11,297 ms | 7,476 ms | 7,321 ms |
| Inserting 500 images | 952 ms | 40 ms | 34 ms |
| 500 formatting operations | 1,783 ms | 86 ms | 96 ms |

Neither article names the hardware. The blog articles [TX Text Control Core vs. Classic Performance Comparison Plain Text to DOCX and PDF](https://www.textcontrol.com/blog/2025/03/31/2025-03-31-tx-text-control-core-vs-classic-performance-comparison-plain-text-to-docx-and-pdf/) and [Benchmarking TX Text Control: Classic vs. Core on Windows and Linux](https://www.textcontrol.com/blog/2025/03/14/benchmarking-tx-text-control-classic-vs-core-on-windows-and-linux/) contain the code.

Processing time turns into server time. Text Control projects from these timings that 10,000 PDF documents of the 5,000-line size, created one after another, take 21.8 hours with Classic and 1.9 hours with Core. The blog article [From Milliseconds to Cloud Costs: The Real Impact of Faster Document Processing in C# .NET](https://www.textcontrol.com/blog/2026/07/24/from-milliseconds-to-cloud-costs-the-real-impact-of-faster-document-processing-in-c-sharp-dot-net/) calls these projections, not production measurements, and lists what changes real results. The Classic engine remains the choice for applications that must load or save DOC files or stay with an existing Classic integration, as [The Document Engine](https://docs.textcontrol.com/tx-text-control-dotnet-server/overview/architecture/#the-document-engine) explains.

### Build Text With Selection Objects

A document built in code from many paragraphs is faster when each piece of text arrives with its formatting: a new `Selection` object with `Text`, `FontName` and `FontSize` assigned to [ServerTextControl.Selection](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/servertextcontrol/selection-property/llms-full.txt) inserts formatted text in one step. Inserting the text, selecting it with `Select` and formatting it afterward takes three.

In Text Control's measurements with the Core engine, documents with 10 sections and 10 to 100 paragraphs per section took 5.7 to 42.9 ms each with Selection objects and 10.6 to 88.9 ms with insert, select and format: about twice as long. The article doesn't name the hardware either. [Insert Formatted Text](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/text/#insert-formatted-text) shows the code, and the blog article [Speed Up Document Generation by Factor 2 Using Selection Objects in .NET C#](https://www.textcontrol.com/blog/2026/07/17/speed-up-document-generation-selection-objects-dotnet-csharp/) the measurements.

### Keep the Internal Format Until the End

The TX Text Control format, `StreamType.InternalUnicodeFormat`, is the format of the engine itself. Text Control recommends it for every step of a document's life in which the document still changes: templates are designed in it, merged without leaving it and edited and reviewed in it. Loading and saving it needs no conversion, and it supports every feature of TX Text Control. The Document Editor saves it with `TXTextControl.StreamType.InternalUnicodeFormat`, and the `DataRowMerged` event of `MailMerge` delivers merged documents in it. Text Control publishes no measurements for this recommendation; the blog article [Document Lifecycle Optimization: Leveraging TX Text Control's Internal Format](https://www.textcontrol.com/blog/2025/05/16/document-lifecycle-optimization-leveraging-tx-text-controls-internal-format/) describes the workflow.

Convert a document to PDF once, when it's final: a PDF that is created before the data and approvals are complete has to be created again. [Create PDF Documents Efficiently](https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/creation/#create-pdf-documents-efficiently) in PDF Creation summarizes this.

### Keep Requests Short

A typical invoice is created in about 300 ms, and an HTTP request can return it directly. Documents that take several seconds, such as merges with many nested merge blocks and thousands of pages, are better accepted by the endpoint, created by a background service and announced when they're ready. For long-running work in ASP.NET Core, Microsoft recommends the `BackgroundService` base class. [Keep the Service Responsive](https://docs.textcontrol.com/tx-text-control-dotnet-server/integration/rest-services/#keep-the-service-responsive) in REST Services describes the pattern, and [Merge Documents With Thousands of Pages](https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/large-documents/#merge-documents-with-thousands-of-pages) the design of long merge templates.

### Separate Processing From Editing

Editing sessions of the Document Editor need a predictable amount of memory, while document processing needs an unpredictable amount of CPU. In one application, heavy processing can block the WebSocket connections of the editors. With many concurrent users, Text Control recommends a separate application for PDF generation, batch mail merges and conversions, which scales on its own. [Container Scaling](https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/container-scaling/llms-full.txt) describes how each part scales.

### Measure Your Own Workload

Text Control publishes no fixed maximum number of `ServerTextControl` instances or documents per second for a server, and the benchmarks above name little of their hardware. Your templates, data, images and fonts decide the numbers. The following program measures the three steps of a merge separately, so that you know which one to improve. It expects a template *template.docx* and a data file *data.json* in the folder of the application, as in [Simple Mail Merge](https://docs.textcontrol.com/tx-text-control-dotnet-server/getting-started/mail-merge/simple/llms-full.txt):

```csharp
using System.Diagnostics;
using TXTextControl;
using TXTextControl.DocumentServer;

string jsonData = File.ReadAllText("data.json");
Stopwatch stopwatch = Stopwatch.StartNew();

using (ServerTextControl tx = new ServerTextControl())
{
    tx.Create();

    LoadSettings loadSettings = new LoadSettings
    {
        ApplicationFieldFormat = ApplicationFieldFormat.MSWord,
        LoadSubTextParts = true
    };

    tx.Load("template.docx", StreamType.WordprocessingML, loadSettings);
    Console.WriteLine($"Load:  {stopwatch.ElapsedMilliseconds} ms");

    stopwatch.Restart();
    using (MailMerge mailMerge = new MailMerge { TextComponent = tx })
    {
        mailMerge.MergeJsonData(jsonData);
    }
    Console.WriteLine($"Merge: {stopwatch.ElapsedMilliseconds} ms");

    stopwatch.Restart();
    tx.Save("result.pdf", StreamType.AdobePDF);
    Console.WriteLine($"Save:  {stopwatch.ElapsedMilliseconds} ms");
}
```

The code works as follows:

- `Stopwatch` from `System.Diagnostics` measures the elapsed time, and `Restart` starts each step at zero.
- [Load](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/servertextcontrol/load-method/llms-full.txt) with the load settings imports the fields and merge blocks of the DOCX template, [MergeJsonData](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol-documentserver/mailmerge/mergejsondata-method/llms-full.txt) merges the data and [Save](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/servertextcontrol/save-method/llms-full.txt) creates the PDF.
- Run the program several times and compare the later runs. Text Control's benchmark of Selection objects warms up every test before it measures it, and the Windows and Linux benchmark averages five runs.

Measure on hardware like your production servers, with the documents your users create. [Multiple Processes](https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/multiple-processes/llms-full.txt) describes how to find the number of parallel workers that gives the highest throughput.

### Next Steps

- [Large Documents](https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/large-documents/llms-full.txt): viewer streaming, request size limits and long merges.
- [Multiple Processes](https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/multiple-processes/llms-full.txt): process large batches in parallel worker processes.
- [Memory Usage](https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/memory-usage/llms-full.txt): what documents and editing sessions need in memory.
- [Container Scaling](https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/container-scaling/llms-full.txt): size the instances of each workload.

---

## Nearby

- **Previous:** [Large Documents](https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/large-documents/llms-full.txt)
- **Next:** [Troubleshooting](https://docs.textcontrol.com/tx-text-control-dotnet-server/troubleshooting/llms-full.txt)
