Adding SelectPdf to a .NET project introduces a noticeable drag on build times. Developers report that builds which previously completed in 12 seconds now take 45 seconds or longer after adding the SelectPdf NuGet package. CI/CD pipelines that once ran quickly now stall waiting for package restoration and file copying. The culprit is the sheer size of the SelectPdf assemblies: packages ranging from 65 MB to over 105 MB that must be downloaded, extracted, and deployed with every build.
The Problem
SelectPdf distributes its PDF generation capabilities through NuGet packages that dwarf typical .NET library sizes. The primary Select.Pdf package weighs 75.61 MB, while the .NET Core variant Select.Pdf.NetCore reaches 105.33 MB. These figures represent the compressed NuGet package size; extracted assembly sizes are even larger.
For comparison, most .NET libraries on NuGet fall between 100 KB and 5 MB. SelectPdf packages are 15 to 100 times larger than the average NuGet dependency. Every clean build must download, extract, and copy these massive assemblies to the output directory.
The problem compounds when using the Blink rendering engine. SelectPdf.NetCore.Blink includes an entire Chromium browser folder (Chromium-124.0.6367.201) that must be deployed alongside the application. This folder contains hundreds of files totaling hundreds of megabytes, all of which must be processed during build and deployment.
Symptoms During Build
Developers observe several performance impacts:
Restoring packages for MyProject.csproj...
GET https://api.nuget.org/v3-flatcontainer/select.pdf.netcore/25.2.0/select.pdf.netcore.25.2.0.nupkg
OK https://api.nuget.org/v3-flatcontainer/select.pdf.netcore/25.2.0/select.pdf.netcore.25.2.0.nupkg 47231ms
Build started...
Copying files to output directory...
Select.Pdf.dll
Select.Html.dep
Select.Tools.dep
Chromium-124.0.6367.201/ (423 files)
Build completed in 67.4 seconds (previously 15.2 seconds)
CI/CD pipeline logs reveal the impact more clearly:
# Azure DevOps Pipeline Output
- task: NuGetCommand@2
displayName: 'Restore NuGet packages'
# Duration: 3m 42s (with SelectPdf)
# Duration: 0m 28s (without SelectPdf)
- task: DotNetCoreCLI@2
displayName: 'Build'
# Duration: 2m 15s (with SelectPdf)
# Duration: 0m 45s (without SelectPdf)
The total build time increase of 4-5 minutes per pipeline run multiplies across daily builds, pull request checks, and deployment cycles.
Who Is Affected
The selectpdf slow build issue impacts several categories of development workflows.
CI/CD Pipeline Impact:
- GitHub Actions workflows exceed free tier minutes faster
- Azure DevOps build minutes consumption increases significantly
- Jenkins agents spend more time per job, reducing throughput
- Docker image builds take longer due to larger layer sizes
- Artifact storage costs increase with 100+ MB deployment packages
Development Machine Impact:
- Clean builds require re-downloading large packages
- Visual Studio Solution Load times increase
- NuGet package cache consumes substantial disk space
- Developers on slower internet connections face extended waits
- Teams with metered connections incur additional data costs
Deployment Impact:
- Azure App Service deployment slots take longer to swap
- Container registry push/pull times increase
- Serverless cold starts carry larger payload overhead
- Kubernetes pod scheduling delays from image pull times
Evidence from the Developer Community
SelectPdf's package size has been noted in multiple technical discussions and comparisons.
Package Size Comparison
| Package | Version | Compressed Size | Notes |
|---|---|---|---|
| Select.Pdf | 25.2.0 | 75.61 MB | .NET Framework version |
| Select.Pdf.NetCore | 25.2.0 | 105.33 MB | .NET Core/.NET 5+ version |
| Select.HtmlToPdf | 25.2.0 | 65.97 MB | HTML conversion focused |
| Select.Pdf.x64 | 25.2.0 | 83.99 MB | 64-bit optimized |
| Select.Pdf.NetCore.Blink | 25.2.0 | Package + Chromium folder | Blink engine version |
Community Observations
Technical comparison articles have noted the build impact:
"SelectPdf can have a big hit on your build time and deploy package size."
-- Technical comparison citing Stack Overflow discussions
The SelectPdf documentation itself acknowledges the file requirements:
"When SelectPdf is installed into your project, a reference to Select.Pdf.dll is created. Besides this assembly, several additional files are needed by SelectPdf: Select.Html.dep, Select.Tools.dep, and Chromium-124.0.6367.201 folder."
-- SelectPdf Installation Documentation
These additional files do not have project references, meaning build systems may not automatically optimize their handling.
Licensing Adds Deployment Concerns
SelectPdf's licensing model ties license tiers to deployment machine counts:
| License Tier | Developers | Deployment Machines | Price (1 Year) |
|---|---|---|---|
| Single Developer | 1 | 1 | $499 |
| 5-Developers | Up to 5 | Up to 10 | $799 |
| Enterprise | Unlimited | Up to 100 | $1,199 |
| Enterprise OEM | Unlimited | Unlimited | $1,599 |
For teams scaling across multiple servers, the per-machine licensing creates cost uncertainty. Only OEM licenses allow unlimited deployment, and cloud deployments specifically require OEM licenses according to SelectPdf documentation. This means a team with 20 production servers, 10 staging servers, and 30 developer machines would need the Enterprise OEM tier regardless of actual usage patterns.
Root Cause Analysis
SelectPdf's assembly size stems from its architectural approach to PDF generation.
Multiple Rendering Engines:
SelectPdf bundles both WebKit and Blink (Chromium) rendering engines. The WebKit engine powers the Select.Html.dep file, while Blink requires a full Chromium installation. Supporting both engines in a single package means carrying the weight of both, even when only one is used.
Native Binary Dependencies:
The Select.Html.dep and Select.Tools.dep files are not .NET assemblies but native executables. These files contain the rendering logic that SelectPdf invokes through inter-process communication. Native binaries cannot be trimmed or optimized by .NET build tools.
Architecture Variants:
SelectPdf provides both x86 and x64 binaries in several packages, doubling the file size for broad compatibility. The x64-specific packages (Select.Pdf.x64) exist to reduce this overhead, but require teams to commit to a single architecture.
No Lazy Loading Architecture:
All SelectPdf binaries must be present at build time and deployed together. There is no option to download rendering components on-demand at runtime, which would allow smaller initial packages.
Attempted Workarounds
Developers have tried several approaches to mitigate selectpdf compilation time impact.
Workaround 1: Use Architecture-Specific Packages
Approach: Install Select.Pdf.x64 instead of the general Select.Pdf package to avoid including 32-bit binaries.
<!-- Instead of -->
<PackageReference Include="Select.Pdf" Version="25.2.0" />
<!-- Use -->
<PackageReference Include="Select.Pdf.x64" Version="25.2.0" />
Limitations:
- Still 83.99 MB package size
- Only works for x64 deployment targets
- Does not reduce Select.Html.dep or Select.Tools.dep sizes
- Breaks builds on x86 systems
Workaround 2: Exclude from Clean Builds
Approach: Configure build to preserve SelectPdf files in output directory between builds.
<PropertyGroup>
<PreserveCompilationContext>true</PreserveCompilationContext>
</PropertyGroup>
<ItemGroup>
<None Update="Select.Html.dep">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
Limitations:
- Does not help CI/CD pipelines that start fresh each run
- Can cause stale binary issues after SelectPdf updates
- Requires manual configuration per project
- Does not reduce package download time
Workaround 3: NuGet Package Caching
Approach: Configure persistent NuGet cache in CI/CD pipelines.
# GitHub Actions example
- name: Cache NuGet packages
uses: actions/cache@v3
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }}
Limitations:
- Cache invalidates on any package version change
- First build in a cache miss scenario still slow
- Cache storage counts against repository limits
- Does not address local development clean builds
Workaround 4: Move PDF Generation to Separate Service
Approach: Isolate SelectPdf into a microservice that builds independently from the main application.
Limitations:
- Significant architectural change
- Introduces network latency for PDF operations
- Adds operational complexity
- Does not eliminate SelectPdf build time, only moves it
A Different Approach: IronPDF
IronPDF provides an alternative architecture that addresses package size concerns differently. While IronPDF also includes Chromium-based rendering, it offers deployment options that reduce build-time impact.
Why IronPDF Addresses Build Time Differently
IronPDF provides the IronPdf.Slim package specifically designed for environments where package size matters. This package contains only the core IronPdf.dll, with native rendering binaries downloaded at runtime when first needed.
Package Size Comparison:
| Package | Size | Native Binaries |
|---|---|---|
| IronPdf (full) | Contains platform binaries | Included in package |
| IronPdf.Slim | Core DLL only | Downloaded at runtime |
| IronPdf.Linux | Linux-optimized | Linux binaries only |
The Slim package approach means:
- CI/CD builds download only the small core package
- Platform-specific binaries download once per deployment target
- Build artifacts remain small for faster artifact transfer
- Different deployment targets can use different binary packages
Code Example
using IronPdf;
/// <summary>
/// Demonstrates IronPDF configuration for minimal build impact.
/// The Slim package approach separates compile-time dependencies
/// from runtime rendering binaries.
/// </summary>
public class BuildOptimizedPdfGenerator
{
public BuildOptimizedPdfGenerator()
{
// When using IronPdf.Slim, enable automatic binary download
// Binaries download once on first use, not during build
Installation.AutomaticallyDownloadNativeBinaries = true;
// Optionally specify a persistent location for binaries
// This prevents re-download across application restarts
Installation.CustomChromiumPath = "/var/lib/ironpdf/chromium";
}
public byte[] GeneratePdf(string htmlContent)
{
// Renderer uses pre-downloaded or just-in-time downloaded binaries
var renderer = new ChromePdfRenderer();
// Configure rendering options
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
// Generate PDF
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
return pdf.BinaryData;
}
}
Key points about this code:
- The
IronPdf.Slimpackage keeps build artifacts small - Native binaries download once at runtime, not during every build
- Binary path configuration allows sharing across deployments
- No architectural changes required compared to SelectPdf migration
CI/CD Pipeline Example
# GitHub Actions workflow demonstrating build optimization
name: Build with IronPdf.Slim
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
# Small package restore - IronPdf.Slim is minimal
- name: Restore dependencies
run: dotnet restore
# Duration: ~30 seconds (vs 3+ minutes with full SelectPdf)
- name: Build
run: dotnet build --no-restore
# Duration: ~45 seconds (consistent with pre-PDF-library times)
# IronPDF binaries download during first test execution
# Subsequent runs use cached binaries
- name: Test
run: dotnet test --no-build
API Reference
For deployment optimization documentation:
Migration Considerations
Licensing
IronPDF uses a different licensing model:
- Lite license: $749 (1 developer, 1 project, perpetual)
- Plus license: $1,499 (3 developers, 3 projects, perpetual)
- Professional license: $2,999 (10 developers, 10 projects, perpetual)
- Unlimited license: $5,999 (unlimited developers and projects, perpetual)
Unlike SelectPdf, IronPDF licenses are not tied to deployment machine counts. A single license covers unlimited servers, containers, and cloud instances for the licensed project count. This simplifies cost planning for scaling deployments.
API Differences
The migration from SelectPdf to IronPDF requires updating class names and method signatures:
SelectPdf:
var converter = new HtmlToPdf();
converter.Options.PdfPageSize = PdfPageSize.A4;
var doc = converter.ConvertHtmlString(html);
doc.Save("output.pdf");
IronPDF:
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
The conceptual mapping is straightforward:
| SelectPdf | IronPDF |
|---|---|
HtmlToPdf |
ChromePdfRenderer |
ConvertHtmlString() |
RenderHtmlAsPdf() |
ConvertUrl() |
RenderUrlAsPdf() |
Options.PdfPageSize |
RenderingOptions.PaperSize |
doc.Save() |
pdf.SaveAs() |
What You Gain
- Significantly smaller build artifacts with IronPdf.Slim
- Deployment-count-independent licensing
- Cross-platform support (Windows, Linux, macOS) from single package
- Runtime binary download option for CI/CD optimization
- Docker and Azure compatibility without elevated tier requirements
What to Consider
- Full IronPDF packages are also large when including all binaries
- Runtime binary download requires internet access on first execution
- Memory usage patterns differ from SelectPdf
- Some SelectPdf-specific features may have different implementations
Conclusion
SelectPdf's 65-105 MB NuGet packages add substantial overhead to build times and CI/CD pipelines. The per-deployment-machine licensing model compounds concerns for scaling applications. While workarounds exist, they address symptoms rather than the fundamental selectpdf assembly size issue. IronPDF's Slim package architecture offers an alternative that keeps build artifacts small while providing runtime binary download, addressing both the compilation time impact and the licensing complexity that teams face when deploying across multiple servers.
Jacob Mellor is CTO at Iron Software, where he leads the technical development of IronPDF and other developer tools.
References
- NuGet Gallery - Select.Pdf{:rel="nofollow"} - Package size and version information
- NuGet Gallery - Select.Pdf.NetCore{:rel="nofollow"} - .NET Core package information
- SelectPdf Installation Documentation{:rel="nofollow"} - Official file deployment requirements
- SelectPdf Pricing{:rel="nofollow"} - License tiers and deployment machine limits
- SelectPdf Deployment Documentation{:rel="nofollow"} - Deployment file requirements
- SelectPdf EULA{:rel="nofollow"} - License terms including deployment restrictions
- IronPdf.Slim Package - Minimal package size option
- IronPDF Package Size Documentation - Package size considerations and options
For the latest IronPDF documentation and tutorials, visit ironpdf.com.
Top comments (0)