Generate, merge, split, shrink, and print PDFs

A practical guide for developers using the PDFluent SDK to build document automation and processing pipelines in Rust.

Automate PDF generation and processing at scale.

Generate thousands of invoices, process incoming PDFs, fill forms, add watermarks, and run PDF pipelines in CI/CD — all from a single Rust binary with no external dependencies.
rust
use pdfluent::{PdfDocument, WatermarkOptions};

fn main() -> pdfluent::Result<()> {
    let mut doc = PdfDocument::open("template.pdf")?;

    doc.form_mut()
        .set_text("customer_name", "ACME Corp")?
        .set_text("date", "2026-01-15")?;

    doc.add_watermark("PROCESSED", WatermarkOptions::centered().opacity(0.15))?;
    doc.save("filled.pdf")?;
    Ok(())
}
How many PDFs can PDFluent process per second?
For typical office documents (form fill and watermark), throughput scales with core count up to I/O saturation. Use Rayon parallelism across cores.
Can I use PDFluent to generate PDFs from HTML or templates?
PDFluent generates PDFs programmatically from Rust code and fills AcroForm templates. Direct HTML-to-PDF conversion is not currently supported — for that use case, generate HTML with your preferred tool and pass the resulting PDF through PDFluent for post-processing operations like watermarking, merging, and compliance validation.
How do I handle documents that fail during batch processing?
Use Rayon's par_iter().map().partition() pattern to separate successes from errors. Write failed paths to an error log and replay only those files after fixing the root cause. PDFluent errors are typed Result values that carry the source file path and error category.
Is it safe to process untrusted uploaded PDFs?
PDFluent does not execute JavaScript or load external resources during parsing. For untrusted input, additionally run the document through a sanitization pass with doc.remove_javascript() and doc.remove_embedded_files() before processing. Consider running batch jobs in a sandboxed container for defence in depth.
Can PDFluent replace a managed PDF service like DocuSign or Adobe PDF Services?
For pure document processing (fill, merge, watermark, compress, validate), yes. PDFluent eliminates per-document API costs that compound at scale. Features requiring legal e-signature infrastructure or cloud storage remain outside the scope of PDFluent, which is a processing library, not a SaaS platform.

Every PDF operation your pipeline needs.

Automate PDF document processing at scale with PDFluent: extract text, split/merge pages, apply redactions, and convert to PDF/A — all in pure Rust.
rust
use pdfluent::PdfDocument;

fn main() -> pdfluent::Result<()> {
    let doc = PdfDocument::open("invoice.pdf")?;

    // Positioned text blocks: text + bounding box + page
    for block in doc.text_with_layout()? {
        println!("p{} {:?} {}", block.page, block.bbox, block.text);
    }
    Ok(())
}
How fast is text extraction?
Text extraction has a median of 70.8 ms on 40 public documents, measured on one MacBook in one release build [A22, 2026-08-24]. Startup is short enough for serverless workloads like AWS Lambda.
Can I run OCR without uploading documents to a server?
In pdfluent 1.1.0, OCR is reachable from Python only: it is opt-in, off by default, and runs through a system tesseract binary on PATH (or PDFLUENT_TESSERACT), or through your own function passed as ocr_function=. From plain Rust, the pdfluent 1.1.0 crate does not reach tesseract (its ocr-tesseract feature is empty). The lower-level Rust crate pdf-engine has optional OCR backends behind feature flags (ocr for the ocrs engine, ocr-cloud for Mistral, Google, AWS and Azure), which the pdfluent 1.1.0 facade does not expose.
Does document processing support batch operations?
Yes. PDFluent supports parallel batch processing with configurable worker threads. You can process thousands of documents per minute with per-document reports in JSON format.
What file formats are supported for conversion?
PDF to DOCX, XLSX, PPTX, PNG, JPEG, SVG, and text. Office formats (DOCX, XLSX, PPTX) to PDF. All conversions preserve layout fidelity and are available in Rust, Python, and Node.js.

Merge and split. Correctly.

Lossless PDF merge and split in Rust — bookmarks, page labels, and named destinations preserved.
rust
use pdfluent::{PdfDocument, PdfMerger, BookmarkMergeStrategy};

fn main() -> pdfluent::Result<()> {
    let merged = PdfMerger::new()
        .add(PdfDocument::open("chapter1.pdf")?)
        .add(PdfDocument::open("chapter2.pdf")?)
        .add(PdfDocument::open("chapter3.pdf")?)
        .with_bookmarks(BookmarkMergeStrategy::Concat)
        .with_page_labels(true)
        .build()?;

    merged.save("book_complete.pdf")?;
    println!("Pages: {}", merged.page_count());
    Ok(())
}
Are bookmarks preserved when merging?
Yes. PDFluent merges the outline trees of source documents into a coherent hierarchy. Nested bookmarks, named destinations, and cross-document links are preserved. The resulting bookmark structure is validated against the PDF specification.
Can I merge linearised PDFs without breaking optimisation?
Yes. PDFluent preserves linearisation structure during merge and split operations. Output files remain web-optimised and load progressively in browsers.
How does PDFluent handle encrypted files?
PDFluent handles password-protected PDFs during merge and split. If you have the user password, you can merge or split encrypted files. Permission flags are respected during all operations.
Can PDFluent handle very large files?
Yes. PDFluent uses streaming operations for large files, avoiding loading entire documents into memory. Merge and split operations on multi-GB PDFs are supported with configurable memory limits.

Split PDFs by page, bookmark, or pattern.

Extract pages, split at bookmarks, or divide by content pattern. Batch split thousands of documents with bookmark and label preservation.
rust
use pdfluent::PdfDocument;

fn main() -> pdfluent::Result<()> {
    let doc = PdfDocument::open("report.pdf")?;

    // Split into single-page documents
    for (i, page) in doc.split_pages()?.into_iter().enumerate() {
        page.save(format!("page-{}.pdf", i + 1))?;
    }

    // Or extract a contiguous range (0-based, end-exclusive)
    doc.extract_pages(0..5)?.save("first-five.pdf")?;
    Ok(())
}
Does splitting preserve interactive form fields?
Yes. Form fields that fall within the extracted page range are preserved in the output document, including their widget annotations and field values. Fields that reference pages outside the range are dropped.
What happens to bookmarks that point to a page outside the split range?
Bookmarks whose destination falls outside the extracted range are removed from the output outline tree. Bookmarks whose destination is within the range are preserved with corrected page offsets.
Can I split a password-protected PDF?
Yes. Open the document with PdfDocument::open_with(path, OpenOptions::new().with_password(...)) using the user password before calling split. The split outputs inherit the same encryption settings unless you explicitly remove them.
How do I split on blank pages instead of bookmarks?
Use SplitBy::BlankPage. PDFluent detects pages whose content stream contains no visible objects (text, images, or paths with non-zero width). This covers separator pages commonly inserted between batched documents.

Shrink PDFs without quality loss.

Compress images, remove duplicate streams, and optimize cross-reference tables to reduce file size on typical documents.
rust
use pdfluent::{PdfDocument, CompressOptions};

fn main() -> pdfluent::Result<()> {
    let mut doc = PdfDocument::open("large.pdf")?;

    let report = doc.compress(CompressOptions::strict())?;
    println!("streams compressed: {}", report.streams_compressed);
    println!("streams deduplicated: {}", report.streams_deduplicated);

    doc.save("compressed.pdf")?;
    Ok(())
}
Will compression change how the PDF looks?
Image downsampling and JPEG re-encoding are lossy operations that can reduce visual quality if you set an aggressive DPI target or low JPEG quality. Stream deduplication, object stream compression, font subsetting, and linearization are all lossless. Use image_quality(ImageQuality::Lossless) to avoid any visual change.
What size reduction can I expect on a typical office document?
A scan-heavy document with uncompressed images typically compresses well. A text-only PDF with embedded subsetted fonts may compress only slightly, because there is little redundancy to remove. Presentation-style PDFs with large background images usually fall in between.
Does compression work on encrypted PDFs?
You must provide the owner password to compress an encrypted PDF, because compression modifies the content streams. The output can be saved with the same encryption settings applied after compression.
What is the difference between linearization and compression?
Compression reduces file size. Linearization reorganizes the byte order so browsers can display page 1 before the entire file is downloaded. They address different problems and can be applied together.

PDF processing that deploys anywhere.

No native dependencies. No JVM. No DLLs. PDFluent runs on Lambda, Cloudflare Workers, and Fly.io straight from a single Rust binary.
rust
use lambda_runtime::{run, service_fn, Error, LambdaEvent};
use pdfluent::PdfDocument;
use serde::{Deserialize, Serialize};

#[derive(Deserialize)]
struct Request {
    /// Base64-encoded PDF bytes
    pdf_b64: String,
}

#[derive(Serialize)]
struct Response {
    page_count: usize,
}

async fn handler(event: LambdaEvent<Request>) -> Result<Response, Error> {
    let bytes = base64::decode(&event.payload.pdf_b64)?;
    let doc = Document::open_bytes(&bytes)?;
    Ok(Response { page_count: doc.page_count() })
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    run(service_fn(handler)).await
}
Why do iText and PDFBox not work well in serverless environments?
iText and PDFBox both require the JVM, which adds to your deployment package and introduces a cold start penalty. Check the provider's current documentation for Lambda package limits. PDFluent has no JVM and no native C/C++ dependencies.
Does PDFluent require a filesystem in serverless environments?
No. All PDFluent APIs accept byte slices as input and return byte slices as output. You never need to write a temp file to disk. This makes PDFluent safe to use in environments where the filesystem is read-only or absent entirely, such as Cloudflare Workers.
Can I use PDFluent on AWS Lambda with the provided.al2023 runtime?
Yes. Compile for x86_64-unknown-linux-musl or aarch64-unknown-linux-musl and the binary will run on any Amazon Linux variant, including al2023. Musl builds are fully statically linked and have no dependency on system libraries.
What is the memory footprint during PDF processing?
For typical documents, PDFluent uses modest heap memory. Configure your Lambda function memory for your document sizes, and check the provider's current documentation for the settings.
How does pricing compare when using PDFluent versus a managed PDF API?
Managed PDF APIs charge per page or per document, typically $0.01–$0.10 per operation. At 100,000 documents per month a managed API costs $1,000–$10,000/mo. With PDFluent on Lambda you pay only for compute time, typically under $5/mo for the same workload.