DOCX-to-PDF is the most common document conversion in .NET, and the right tool depends entirely on your deployment target. Interop needs Word installed — fine for an on-premises Windows server, impossible in a Linux container. Spire.Doc is cross-platform but the free tier caps at 3 pages. The ChangeThisFile API runs LibreOffice headless server-side so your container stays lean.

Method 1: Spire.Doc (cross-platform, no Word required)

Spire.Doc Free converts DOCX to PDF on Windows, Linux, and macOS. The free edition limits output to 3 pages; beyond that you need Spire.Doc (paid) or the API.

dotnet add package Spire.Doc
using Spire.Doc;

public static class DocxToPdf
{
    /// <summary>Converts a DOCX file to PDF. Works on Linux/macOS without Word.</summary>
    public static void Convert(string inputPath, string outputPath)
    {
        using var document = new Document();
        document.LoadFromFile(inputPath);
        document.SaveToFile(outputPath, FileFormat.PDF);
    }
}

// Usage
DocxToPdf.Convert("report.docx", "report.pdf");
Console.WriteLine("Done");

Spire.Doc renders fonts, tables, images, headers, footers, and most Word styles. Complex tracked-changes documents may differ slightly from Word's rendering — check the output for high-stakes documents.

Method 2: Microsoft.Office.Interop.Word (highest fidelity, Windows only)

Interop drives a live Word instance via COM. Output is pixel-perfect because it IS Word — but Word must be installed, and COM objects must be released carefully or Word processes leak.

dotnet add package Microsoft.Office.Interop.Word
# Requires Word installed on the machine. Windows only.
using Microsoft.Office.Interop.Word;
using System.Runtime.InteropServices;

public static class DocxToPdfInterop
{
    public static void Convert(string inputPath, string outputPath)
    {
        Application? wordApp = null;
        Document? doc = null;
        try
        {
            wordApp = new Application { Visible = false };
            doc = wordApp.Documents.Open(
                Path.GetFullPath(inputPath),
                ReadOnly: true,
                Visible: false);

            doc.SaveAs2(
                Path.GetFullPath(outputPath),
                WdSaveFormat.wdFormatPDF);
        }
        finally
        {
            doc?.Close(WdSaveOptions.wdDoNotSaveChanges);
            wordApp?.Quit();

            if (doc != null) Marshal.ReleaseComObject(doc);
            if (wordApp != null) Marshal.ReleaseComObject(wordApp);
        }
    }
}

Always release COM objects in a finally block. Leaked Word processes accumulate and eventually exhaust available memory. Do not use Interop in ASP.NET — it is not thread-safe and Microsoft explicitly does not support it in server scenarios.

Method 3: ChangeThisFile API (HttpClient, no Word or LibreOffice)

The API runs LibreOffice headless. Handles documents of any page count, runs on your existing HttpClient, no native deps. Free tier: 1,000 conversions/month.

# Verify with curl first
curl -X POST https://changethisfile.com/v1/convert \
  -H "Authorization: Bearer ctf_sk_your_key" \
  -F "file=@report.docx" \
  -F "target=pdf" \
  --output report.pdf
using System.Net.Http;
using System.Net.Http.Headers;

// Register in Program.cs:
// builder.Services.AddHttpClient("ctf",
//     c => c.BaseAddress = new Uri("https://changethisfile.com"));

public class DocxToPdfService
{
    private readonly HttpClient _http;
    private const string ApiKey = "ctf_sk_your_key_here";

    public DocxToPdfService(IHttpClientFactory factory)
        => _http = factory.CreateClient("ctf");

    public async Task ConvertAsync(
        string inputPath,
        string outputPath,
        CancellationToken ct = default)
    {
        await using var fileStream = File.OpenRead(inputPath);
        using var form = new MultipartFormDataContent();

        var fileContent = new StreamContent(fileStream);
        fileContent.Headers.ContentType = new MediaTypeHeaderValue(
            "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
        form.Add(fileContent, "file", Path.GetFileName(inputPath));
        form.Add(new StringContent("pdf"), "target");

        using var request = new HttpRequestMessage(HttpMethod.Post, "/v1/convert")
        {
            Content = form,
            Headers = { Authorization =
                new AuthenticationHeaderValue("Bearer", ApiKey) }
        };

        using var response = await _http.SendAsync(request, ct);
        response.EnsureSuccessStatusCode();

        await using var outStream = File.Create(outputPath);
        await response.Content.CopyToAsync(outStream, ct);
    }
}

When to use each

ApproachBest forTradeoff
Spire.DocCross-platform, no Word, documents ≤3 pages (free)Free tier page cap; paid license for longer docs
Office InteropPixel-perfect fidelity, Windows server with WordWindows only, not thread-safe, COM leak risk
ChangeThisFile APILinux containers, any page count, no native depsNetwork call; 25MB file limit on free tier

Production tips

  • Never use Interop in ASP.NET. Microsoft explicitly states Office automation is not supported in server scenarios. Use Spire.Doc or the API for web applications.
  • Use IHttpClientFactory. Register a named client once in Program.cs with base address and timeout. Inject IHttpClientFactory into your service — avoids socket exhaustion from repeated new HttpClient().
  • Pass CancellationToken through. Wire HttpContext.RequestAborted so a cancelled HTTP request propagates to the file I/O and the API call, not just to the outer await.
  • Stream the upload. Open the file with File.OpenRead and pass the stream to StreamContent. Don't ReadAllBytes into memory for large documents.
  • Set a conversion timeout. Large DOCX files (many embedded images) can take 10–30 seconds through LibreOffice. Set client.Timeout = TimeSpan.FromMinutes(2) in your named HttpClient config.
  • Font embedding matters. If your DOCX uses non-standard fonts and you're on Linux, LibreOffice may substitute them. Embed fonts in the DOCX before converting, or stick to standard fonts like Calibri, Arial, Times New Roman.

For Linux containers and web services, Spire.Doc (or the API for large docs) is the correct choice — Office Interop has no place in server-side .NET. For internal Windows tooling where Word is already present, Interop gives the highest fidelity. Free tier: 1,000 conversions/month.