Skip to footer content
USING IRONPDF

How to Merge PDF Byte Arrays in C#

Create PdfDocument objects from your byte arrays and use PdfDocument.Merge() to combine them into a single PDF without saving to disk. This method handles the complex PDF structure automatically, allowing you to merge documents stored in databases or received from APIs without ever writing temporary files.

Working with PDF files stored as byte arrays is common in modern C# applications. Whether you are retrieving PDF documents from a database, receiving them from web services, or processing them in memory, the ability to merge multiple PDF files into one without saving to disk is essential for enterprise workflows. IronPDF makes this straightforward with an intuitive API. In this article, you will walk through how to merge PDF byte arrays in C#, examining different approaches including MemoryStream handling and real-world database patterns.

What Are PDF Byte Arrays and Why Merge Them?

A byte array is raw binary data representing a PDF file in memory. When working with PDF documents in C#, you will often encounter scenarios where files exist as byte arrays rather than on disk. This is particularly common when retrieving documents from databases where PDFs are stored as binary columns, or when receiving documents from REST APIs.

The MemoryStream functionality in .NET -- documented in the Microsoft MemoryStream reference -- makes handling these byte arrays efficient, especially when combined with proper memory management for large documents. Rather than writing temporary files, you can load, process, and save PDFs entirely in memory -- which is faster, cleaner, and avoids file system permission issues.

Why Can't You Just Concatenate PDF Byte Arrays?

Simply concatenating two PDF byte arrays will not work. Unlike plain text files, PDF files have complex internal structures with headers, cross-reference tables, and specific formatting conventions. The ISO 32000 PDF specification defines intricate rules about document structure, including metadata, font embedding, and encryption layers. Joining the bytes directly produces a corrupt file. You need a proper PDF library to parse those byte arrays and combine them correctly while preserving all structural integrity.

IronPDF handles all this complexity internally. You can merge PDF documents with just a few lines of code while preserving fonts, images, and formatting exactly as they appeared in the source files.

When Should You Use Byte Array Merging?

This approach works well when:

  • Documents are stored in a SQL Server or PostgreSQL database as binary columns
  • Your application receives PDF data from an external API or microservice
  • You are processing file uploads in ASP.NET without saving them to disk
  • You are running in a cloud environment like Azure Functions or AWS Lambda where temporary file storage is restricted

When working with Azure Blob Storage or similar cloud services, byte array manipulation becomes essential because you download the raw bytes, process them, and upload the result -- all without touching the file system.

How Do You Add the PDF Library to Your Project?

Getting started requires adding the IronPDF NuGet package to your project. The package is available on NuGet.org. You can install it using either the Package Manager Console or the .NET CLI:

Install-Package IronPdf
Install-Package IronPdf
SHELL
dotnet add package IronPdf
dotnet add package IronPdf
SHELL

For detailed installation options including Docker deployment or Linux setup, see the advanced installation guide. If you are deploying to a minimal environment, IronPDF Slim reduces the deployment footprint significantly.

Once installed, add the following namespaces at the top of your C# file:

using IronPdf;
using System.IO;
using System.Collections.Generic;
using IronPdf;
using System.IO;
using System.Collections.Generic;
$vbLabelText   $csharpLabel

IronPDF supports Windows, macOS, and Linux platforms. It integrates with ASP.NET Core, Blazor, console applications, and cloud environments without any additional configuration.

Visual Studio's NuGet Package Manager interface displaying IronPDF library search results, with version 2025.9.4 selected for installation in the IronTesting project - showing the Install button and version dropdown prominently

Get stated with IronPDF now.
green arrow pointer

How Do You Merge Two PDF Byte Arrays in C#?

Here is a complete example demonstrating how to merge two PDF byte arrays into a single PDF document:

// Simulate two PDF byte arrays (in practice, these come from a database or API)
byte[] pdfBytes1 = File.ReadAllBytes("document1.pdf");
byte[] pdfBytes2 = File.ReadAllBytes("document2.pdf");

// Create PdfDocument objects from byte arrays
var pdf1 = new PdfDocument(pdfBytes1);
var pdf2 = new PdfDocument(pdfBytes2);

// Merge the two PDF documents
PdfDocument combinedPdf = PdfDocument.Merge(pdf1, pdf2);

// Convert the combined PDF back to a byte array
byte[] mergedPdfBytes = combinedPdf.BinaryData;

// Optionally save the merged PDF to disk
File.WriteAllBytes("merged.pdf", mergedPdfBytes);
// Simulate two PDF byte arrays (in practice, these come from a database or API)
byte[] pdfBytes1 = File.ReadAllBytes("document1.pdf");
byte[] pdfBytes2 = File.ReadAllBytes("document2.pdf");

// Create PdfDocument objects from byte arrays
var pdf1 = new PdfDocument(pdfBytes1);
var pdf2 = new PdfDocument(pdfBytes2);

// Merge the two PDF documents
PdfDocument combinedPdf = PdfDocument.Merge(pdf1, pdf2);

// Convert the combined PDF back to a byte array
byte[] mergedPdfBytes = combinedPdf.BinaryData;

// Optionally save the merged PDF to disk
File.WriteAllBytes("merged.pdf", mergedPdfBytes);
$vbLabelText   $csharpLabel

The PdfDocument class accepts raw byte arrays directly in its constructor. Once you have two PdfDocument instances, PdfDocument.Merge() combines them into a single document. The BinaryData property then gives you the result as a byte array, ready to store back in a database or transmit via an API.

The PdfDocument API provides extensive functionality beyond simple merging, including page manipulation, text extraction, and form handling. Once you have a merged document, you can apply any of these operations before extracting the final byte array.

What Does the Merged Output Look Like?

PDF viewer displaying successfully merged PDF documents with 'PDF One' on page 1 and 'PDF Two' on page 2, demonstrating clear document boundaries and preserved formatting at 100% zoom

The output is a single PDF containing all pages from both source documents in the order they were passed to Merge(). Page numbering, fonts, images, and embedded content are all preserved. The merged document behaves identically to any other PDF -- you can paginate, annotate, sign, or compress it using the same IronPDF methods you would apply to any document.

How Does the Merge Process Work Internally?

When you pass a byte array to the PdfDocument constructor, IronPDF parses the binary data and builds an in-memory representation of the PDF structure. The PdfDocument.Merge() method then combines multiple documents by appending pages from each source in sequence, rebuilding the cross-reference table, and resolving any font or resource name conflicts between documents.

This is why you cannot simply concatenate byte arrays -- the cross-reference table in the first PDF points to offsets within that file. After concatenation, those offsets are invalid because the second file has shifted them. IronPDF rebuilds the entire structure correctly, resulting in a valid, well-formed PDF.

How Do You Merge More Than Two PDF Files at Once?

IronPDF provides a List overload for merging any number of documents in a single operation. This is more efficient than chaining multiple two-document merges:

// Load four PDFs as byte arrays
List<byte[]> pdfByteArrays = new List<byte[]>
{
    File.ReadAllBytes("example1.pdf"),
    File.ReadAllBytes("example2.pdf"),
    File.ReadAllBytes("example3.pdf"),
    File.ReadAllBytes("example4.pdf")
};

// Convert each byte array to a PdfDocument
List<PdfDocument> pdfsToMerge = new List<PdfDocument>();
for (int i = 0; i < pdfByteArrays.Count; i++)
{
    pdfsToMerge.Add(new PdfDocument(pdfByteArrays[i]));
}

// Merge all documents in one call
PdfDocument combinedPdf = PdfDocument.Merge(pdfsToMerge);
byte[] finalPdfBytes = combinedPdf.BinaryData;

// Apply compression if the result is large
if (finalPdfBytes.Length > 1024 * 1024 * 10) // 10 MB
{
    combinedPdf.CompressImages(90);
    finalPdfBytes = combinedPdf.BinaryData;
}
// Load four PDFs as byte arrays
List<byte[]> pdfByteArrays = new List<byte[]>
{
    File.ReadAllBytes("example1.pdf"),
    File.ReadAllBytes("example2.pdf"),
    File.ReadAllBytes("example3.pdf"),
    File.ReadAllBytes("example4.pdf")
};

// Convert each byte array to a PdfDocument
List<PdfDocument> pdfsToMerge = new List<PdfDocument>();
for (int i = 0; i < pdfByteArrays.Count; i++)
{
    pdfsToMerge.Add(new PdfDocument(pdfByteArrays[i]));
}

// Merge all documents in one call
PdfDocument combinedPdf = PdfDocument.Merge(pdfsToMerge);
byte[] finalPdfBytes = combinedPdf.BinaryData;

// Apply compression if the result is large
if (finalPdfBytes.Length > 1024 * 1024 * 10) // 10 MB
{
    combinedPdf.CompressImages(90);
    finalPdfBytes = combinedPdf.BinaryData;
}
$vbLabelText   $csharpLabel

This approach scales to any number of documents. Each PDF is loaded into a PdfDocument object, added to a list, and then merged in a single call. For large output files, PDF compression reduces the final size without losing meaningful quality.

When Should You Use MemoryStream for PDF Merging?

The MemoryStream approach gives you more control when integrating with other .NET libraries that work with streams rather than byte arrays. It is also useful when you already have a stream available (for example, from an HTTP response or a blob storage SDK):

using (var stream1 = new MemoryStream(pdfBytes1))
using (var stream2 = new MemoryStream(pdfBytes2))
{
    var pdf1 = new PdfDocument(stream1);
    var pdf2 = new PdfDocument(stream2);

    var merged = PdfDocument.Merge(pdf1, pdf2);

    // Add metadata to the merged document
    merged.MetaData.Author = "Your Application";
    merged.MetaData.Title = "Merged Document";
    merged.MetaData.CreationDate = DateTime.Now;

    byte[] result = merged.BinaryData;
}
using (var stream1 = new MemoryStream(pdfBytes1))
using (var stream2 = new MemoryStream(pdfBytes2))
{
    var pdf1 = new PdfDocument(stream1);
    var pdf2 = new PdfDocument(stream2);

    var merged = PdfDocument.Merge(pdf1, pdf2);

    // Add metadata to the merged document
    merged.MetaData.Author = "Your Application";
    merged.MetaData.Title = "Merged Document";
    merged.MetaData.CreationDate = DateTime.Now;

    byte[] result = merged.BinaryData;
}
$vbLabelText   $csharpLabel

You can enrich the merged document by setting metadata, adding watermarks, or applying digital signatures before extracting the final bytes. For compliance scenarios, consider PDF/A conversion for long-term archival or PDF/UA compliance for accessibility requirements.

Stream-based processing provides better memory management for larger PDF files and integrates cleanly with cloud storage SDKs. This approach is especially practical for async patterns in high-throughput services.

How Do You Merge PDFs Retrieved from a Database?

A common real-world pattern involves fetching PDF byte arrays from a SQL database and combining them on demand. Here is a production-ready example with error handling:

public string MergePdfDocumentsFromDatabase(List<int> documentIds)
{
    List<PdfDocument> documents = new List<PdfDocument>();

    try
    {
        foreach (int id in documentIds)
        {
            // Fetch PDF byte array from database
            byte[] pdfData = GetPdfFromDatabase(id); // Replace with your data access logic

            if (pdfData == null || pdfData.Length == 0)
            {
                Console.WriteLine($"Warning: Document {id} is empty or not found");
                continue;
            }

            documents.Add(new PdfDocument(pdfData));
        }

        if (documents.Count == 0)
        {
            return "Error: No valid documents found to merge";
        }

        // Merge all documents
        PdfDocument mergedDocument = PdfDocument.Merge(documents);

        // Add page numbers to the footer
        mergedDocument.AddHtmlFooters(new HtmlHeaderFooter()
        {
            HtmlFragment = "<center>Page {page} of {total-pages}</center>",
            DrawDividerLine = true
        });

        // Save back to the database
        byte[] resultBytes = mergedDocument.BinaryData;
        SaveMergedPdfToDatabase(resultBytes);

        return "Document successfully combined and saved.";
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Error merging PDFs: {ex.Message}");
        return $"Merge failed: {ex.Message}";
    }
}
public string MergePdfDocumentsFromDatabase(List<int> documentIds)
{
    List<PdfDocument> documents = new List<PdfDocument>();

    try
    {
        foreach (int id in documentIds)
        {
            // Fetch PDF byte array from database
            byte[] pdfData = GetPdfFromDatabase(id); // Replace with your data access logic

            if (pdfData == null || pdfData.Length == 0)
            {
                Console.WriteLine($"Warning: Document {id} is empty or not found");
                continue;
            }

            documents.Add(new PdfDocument(pdfData));
        }

        if (documents.Count == 0)
        {
            return "Error: No valid documents found to merge";
        }

        // Merge all documents
        PdfDocument mergedDocument = PdfDocument.Merge(documents);

        // Add page numbers to the footer
        mergedDocument.AddHtmlFooters(new HtmlHeaderFooter()
        {
            HtmlFragment = "<center>Page {page} of {total-pages}</center>",
            DrawDividerLine = true
        });

        // Save back to the database
        byte[] resultBytes = mergedDocument.BinaryData;
        SaveMergedPdfToDatabase(resultBytes);

        return "Document successfully combined and saved.";
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Error merging PDFs: {ex.Message}");
        return $"Merge failed: {ex.Message}";
    }
}
$vbLabelText   $csharpLabel

This pattern handles missing or null records gracefully by skipping them and continuing with valid documents. The merged result gets page numbers added via HTML headers/footers before being written back to the database. For more advanced navigation, you can add bookmarks to help readers navigate a long merged document.

What Makes the Database Pattern Effective?

The pattern above works for invoices, reports, contracts, or any documents stored as binary columns. Key advantages:

  • No temporary files: The entire workflow happens in memory, which avoids file system access and reduces attack surface.
  • Graceful skipping: Invalid or missing records do not abort the entire merge -- they are logged and skipped.
  • Enrichment before saving: Adding footers or metadata to the merged document happens before the final byte array is extracted, so the result is complete and ready to use.
  • Single database write: The merged result is written once, keeping database transactions simple.

How Do You Handle Errors and Edge Cases?

What Are the Most Common Error Scenarios?

When building PDF merge workflows, several failure modes are worth guarding against:

  1. Null or empty byte arrays: The most common issue. Always check pdfData != null && pdfData.Length > 0 before constructing a PdfDocument.
  2. Corrupt or invalid PDF data: If the byte array was truncated during database storage or API transmission, the constructor will throw. Wrap in a try-catch and log the document ID.
  3. Encrypted PDFs without passwords: Attempting to merge a password-protected PDF without supplying the password throws an exception. Use IronPDF's password-protected PDF handling to supply credentials.
  4. Memory pressure with many large files: Loading dozens of large PDFs simultaneously can strain available memory. Process them in batches and dispose of PdfDocument objects after merging.

Here is a reliable pattern with input validation:

public bool TryMergePdfByteArrays(byte[] pdfBytes1, byte[] pdfBytes2, out byte[] mergedBytes)
{
    mergedBytes = null;

    try
    {
        if (pdfBytes1 == null || pdfBytes1.Length == 0)
            throw new ArgumentException("First PDF byte array is null or empty");

        if (pdfBytes2 == null || pdfBytes2.Length == 0)
            throw new ArgumentException("Second PDF byte array is null or empty");

        using var pdf1 = new PdfDocument(pdfBytes1);
        using var pdf2 = new PdfDocument(pdfBytes2);

        if (pdf1.PageCount == 0)
            throw new InvalidOperationException("First PDF has no pages");

        if (pdf2.PageCount == 0)
            throw new InvalidOperationException("Second PDF has no pages");

        var mergedPdf = PdfDocument.Merge(pdf1, pdf2);
        mergedBytes = mergedPdf.BinaryData;

        return true;
    }
    catch (Exception ex)
    {
        Console.WriteLine($"PDF merge failed: {ex.Message}");
        return false;
    }
}
public bool TryMergePdfByteArrays(byte[] pdfBytes1, byte[] pdfBytes2, out byte[] mergedBytes)
{
    mergedBytes = null;

    try
    {
        if (pdfBytes1 == null || pdfBytes1.Length == 0)
            throw new ArgumentException("First PDF byte array is null or empty");

        if (pdfBytes2 == null || pdfBytes2.Length == 0)
            throw new ArgumentException("Second PDF byte array is null or empty");

        using var pdf1 = new PdfDocument(pdfBytes1);
        using var pdf2 = new PdfDocument(pdfBytes2);

        if (pdf1.PageCount == 0)
            throw new InvalidOperationException("First PDF has no pages");

        if (pdf2.PageCount == 0)
            throw new InvalidOperationException("Second PDF has no pages");

        var mergedPdf = PdfDocument.Merge(pdf1, pdf2);
        mergedBytes = mergedPdf.BinaryData;

        return true;
    }
    catch (Exception ex)
    {
        Console.WriteLine($"PDF merge failed: {ex.Message}");
        return false;
    }
}
$vbLabelText   $csharpLabel

The using statements ensure that PdfDocument objects are disposed correctly, releasing unmanaged resources even if an exception occurs. The TryXxx pattern returns a boolean success indicator rather than throwing, making it easy to call from higher-level code that handles multiple documents.

How Can You Prevent Common Mistakes?

Several habits reduce the risk of production failures:

  • Validate before loading: Check that byte arrays are non-null and have a minimum plausible length (PDF headers are at least a few hundred bytes).
  • Use using for disposal: IronPDF documents hold native resources. Always dispose them, either with using statements or explicit Dispose() calls.
  • Enable custom logging: Log the document ID, byte array length, and page count whenever merging documents from a database. This makes debugging production issues far easier.
  • Handle encrypted PDFs explicitly: Check whether a document requires a password before merging. Attempting to read an encrypted document without credentials throws an exception rather than returning empty pages.
  • Set timeouts for complex documents: Very large or complex PDFs can take time to process. Consider async operations and appropriate timeout values for high-volume scenarios.
PDF Merge Approach Comparison
Approach Best For Memory Use Flexibility
Direct byte array (two files) Simple two-document merge Low Basic
List<PdfDocument> overload Batch merging many files Medium High
MemoryStream constructor Stream-based integrations Low High
Database fetch pattern Production document workflows Medium Very High

How Do You Get Started with PDF Merging in Production?

IronPDF provides a full-featured free trial so you can test PDF merging in your actual application before committing to a license. The trial includes the complete API -- merge, split, convert, annotate, sign, and more -- with no feature restrictions during evaluation.

For production use, licensing options range from single-developer licenses to enterprise site licenses covering unlimited deployments. Organizations running high-volume workflows can explore OEM licensing for redistributable scenarios.

Beyond merging, IronPDF covers the full PDF processing lifecycle: HTML to PDF conversion, PDF editing, form creation and filling, text extraction, digital signatures, and security management. Once you have the merge workflow working, these features slot in without any additional dependencies.

Visit the IronPDF tutorials page to explore complete walkthroughs for each major capability, or check the API reference for detailed documentation on every class and method.

NuGet Install with NuGet

PM >  Install-Package IronPdf

Check out IronPDF on NuGet for quick installation. With over 10 million downloads, it’s transforming PDF development with C#. You can also download the DLL or Windows installer.

Frequently Asked Questions

How can I merge two PDF byte arrays using C#?

You can merge two PDF byte arrays in C# by utilizing IronPDF. The library allows you to easily combine multiple PDF files stored as byte arrays, memory streams, or even databases with straightforward code examples.

What is the advantage of using IronPDF for merging PDF byte arrays?

IronPDF simplifies the process of merging PDF byte arrays by providing intuitive functions that handle the complexities of PDF manipulation, ensuring efficient and reliable results.

Can IronPDF handle merging PDFs from different data sources?

Yes, IronPDF can merge PDFs from various data sources, including byte arrays, memory streams, and databases, making it a versatile tool for PDF file manipulation.

Is it possible to combine PDFs stored in memory streams with IronPDF?

Absolutely, IronPDF supports combining PDFs stored in memory streams, allowing seamless integration and merging capabilities directly in your C# applications.

Does IronPDF require any additional software to merge PDF byte arrays?

No, IronPDF is a standalone library that does not require additional software to merge PDF byte arrays. It's designed to integrate easily within your C# project.

How does IronPDF ensure the quality of the merged PDFs?

IronPDF maintains the original quality and formatting of the PDFs during the merging process, ensuring that the final document is of high quality and preserves all original content.

What file formats can IronPDF output after merging PDF byte arrays?

After merging, IronPDF can output the final document in standard PDF format, ensuring compatibility with any PDF viewer or editor.

Can IronPDF merge encrypted PDF byte arrays?

Yes, IronPDF can handle encrypted PDF byte arrays, provided you have the necessary permissions and pass the correct credentials for decryption during the merging process.

What coding knowledge is required to use IronPDF for merging PDF byte arrays?

Basic knowledge of C# is sufficient to use IronPDF for merging PDF byte arrays, as the library offers straightforward methods and comprehensive documentation to guide you through the process.

Is there any support available for troubleshooting issues with IronPDF?

Yes, IronPDF offers comprehensive documentation and support to help troubleshoot any issues that may arise while using the library for PDF manipulation tasks.

Curtis Chau
Technical Writer

Curtis Chau holds a Bachelor’s degree in Computer Science (Carleton University) and specializes in front-end development with expertise in Node.js, TypeScript, JavaScript, and React. Passionate about crafting intuitive and aesthetically pleasing user interfaces, Curtis enjoys working with modern frameworks and creating well-structured, visually appealing manuals.

...

Read More

Iron Support Team

We're online 24 hours, 5 days a week.
Chat
Email
Call Me