How to Print PDF Files Using Node.js

Printing a PDF file in Node.js requires sending the document to the operating system's print spooler. The pdf-to-printer npm package abstracts that system call into a promise-based API that works on Windows, macOS, and Linux, letting you queue a print job in a single method call. For PDF generation before printing -- converting HTML, URLs, or templates to print-ready documents -- IronPDF for Node.js pairs naturally with this workflow.

Quickstart: Print a PDF File in Node.js

//:path=/static-assets/pdf/content-code-examples/nodejs/how-to/nodejs-print-pdf/quickstart.js
// 1. Install: npm install pdf-to-printer
const printer = require('pdf-to-printer');

// 2. Print the PDF file (returns a Promise)
printer
  .print('./invoice.pdf')
  .then(() => console.log('Print job queued successfully.'))
  .catch((err) => console.error('Print failed:', err));
//:path=/static-assets/pdf/content-code-examples/nodejs/how-to/nodejs-print-pdf/quickstart.js
// 1. Install: npm install pdf-to-printer
const printer = require('pdf-to-printer');

// 2. Print the PDF file (returns a Promise)
printer
  .print('./invoice.pdf')
  .then(() => console.log('Print job queued successfully.'))
  .catch((err) => console.error('Print failed:', err));
JAVASCRIPT

What Are the Prerequisites for Printing PDFs in Node.js?

Node.js 14.x or later and npm are required before using pdf-to-printer. The package relies on native OS print commands rather than a bundled print engine, so printer drivers must already be configured on the target machine.

On Windows, the package calls SumatraPDF via PowerShell. Ensure PowerShell script execution is not blocked by your system policy. On macOS and Linux, the package delegates to the lp command, which is part of the CUPS printing system. Confirm CUPS is installed and that at least one printer is registered with lpstat -p.

Please noteNode.js 18.x LTS is recommended for production workloads. The pdf-to-printer package supports all active Node.js LTS versions.

How Do I Set Up a Node.js Project for PDF Printing?

Initialize a new project, install the package, and create a minimal directory structure before writing any printing logic.

//:path=/static-assets/pdf/content-code-examples/nodejs/how-to/nodejs-print-pdf/setup.sh
mkdir pdf-printer
cd pdf-printer
npm init -y
npm install pdf-to-printer
//:path=/static-assets/pdf/content-code-examples/nodejs/how-to/nodejs-print-pdf/setup.sh
mkdir pdf-printer
cd pdf-printer
npm init -y
npm install pdf-to-printer
SHELL

After installation, create an index.js file for your printing logic and a pdfs/ folder to hold the documents you want to print. A separate config.js for printer settings keeps printer names out of your core logic -- a useful pattern for multi-environment deployments where the target printer differs between development and production.

The module uses native bindings that resolve at runtime, so no compile step is required. The node_modules/pdf-to-printer/dist/ directory will contain pre-built binaries for the detected platform.

How Do I Print a PDF File with Basic Usage?

Pass the absolute or relative file path to printer.print(). The method queues the document with the system default printer and resolves the Promise once the job is accepted by the spooler -- not when physical printing is complete.

//:path=/static-assets/pdf/content-code-examples/nodejs/how-to/nodejs-print-pdf/basic-print.js
const fs = require('fs').promises;
const printer = require('pdf-to-printer');

async function printPDF(filePath) {
  // Verify the file exists before sending to printer
  await fs.access(filePath);

  const stats = await fs.stat(filePath);
  if (stats.size === 0) {
    throw new Error('PDF file is empty');
  }

  await printer.print(filePath);
  console.log(`Print job queued: ${filePath}`);
}

printPDF('./pdfs/invoice.pdf').catch((err) => {
  if (err.code === 'ENOENT') {
    console.error('File not found:', err.path);
  } else {
    console.error('Print error:', err.message);
  }
});
//:path=/static-assets/pdf/content-code-examples/nodejs/how-to/nodejs-print-pdf/basic-print.js
const fs = require('fs').promises;
const printer = require('pdf-to-printer');

async function printPDF(filePath) {
  // Verify the file exists before sending to printer
  await fs.access(filePath);

  const stats = await fs.stat(filePath);
  if (stats.size === 0) {
    throw new Error('PDF file is empty');
  }

  await printer.print(filePath);
  console.log(`Print job queued: ${filePath}`);
}

printPDF('./pdfs/invoice.pdf').catch((err) => {
  if (err.code === 'ENOENT') {
    console.error('File not found:', err.path);
  } else {
    console.error('Print error:', err.message);
  }
});
JAVASCRIPT

Checking file existence before calling printer.print() prevents silent failures when a path is wrong or a file has been moved. The fs.access() call throws ENOENT if the path does not resolve, giving you a descriptive error rather than a generic spooler rejection. Common error causes include incorrect relative paths, missing printer drivers, and printer offline status.

ImportantThe Promise resolves when the print job is accepted by the OS spooler, not when the document finishes printing. For auditing purposes, record the timestamp at resolution rather than assuming the document has left the printer.

How Do I Generate a PDF Before Printing?

When the document does not already exist as a file, generate it with IronPDF for Node.js before calling printer.print(). IronPDF renders HTML, URLs, and template strings into print-ready PDF files without requiring a separate browser instance.

//:path=/static-assets/pdf/content-code-examples/nodejs/how-to/nodejs-print-pdf/generate-and-print.js
const { PdfDocument } = require('@ironsoftware/ironpdf');
const printer = require('pdf-to-printer');

async function generateAndPrint(htmlContent, outputPath) {
  // Render HTML to a PDF file using IronPDF
  const pdf = await PdfDocument.fromHtml(htmlContent);
  await pdf.saveAs(outputPath);

  // Send the generated file to the default printer
  await printer.print(outputPath);
  console.log(`Generated and printed: ${outputPath}`);
}

generateAndPrint('<h1>Monthly Report</h1><p>Sales data for May 2026.</p>', './pdfs/report.pdf');
//:path=/static-assets/pdf/content-code-examples/nodejs/how-to/nodejs-print-pdf/generate-and-print.js
const { PdfDocument } = require('@ironsoftware/ironpdf');
const printer = require('pdf-to-printer');

async function generateAndPrint(htmlContent, outputPath) {
  // Render HTML to a PDF file using IronPDF
  const pdf = await PdfDocument.fromHtml(htmlContent);
  await pdf.saveAs(outputPath);

  // Send the generated file to the default printer
  await printer.print(outputPath);
  console.log(`Generated and printed: ${outputPath}`);
}

generateAndPrint('<h1>Monthly Report</h1><p>Sales data for May 2026.</p>', './pdfs/report.pdf');
JAVASCRIPT

This pattern is common in reporting workflows where PDF content is assembled at runtime from database records or API responses. See the HTML to PDF conversion tutorial for a full walkthrough of IronPDF's rendering options, including CSS support and header/footer injection.

How Do I Specify Custom Printer Options?

Pass a printerOptions object as the second argument to printer.print() to target a specific printer, set the copy count, select page ranges, or control page scaling. The printer name must match the exact value returned by printer.getPrinters().

//:path=/static-assets/pdf/content-code-examples/nodejs/how-to/nodejs-print-pdf/custom-options.js
const printer = require('pdf-to-printer');

async function printWithOptions(filePath) {
  // List available printers to find the correct name
  const printers = await printer.getPrinters();
  printers.forEach((p) => {
    console.log(`${p.name} -- default: ${p.isDefault}`);
  });

  const options = {
    printer: 'HP LaserJet Pro',  // Exact name from getPrinters()
    copies: 2,                   // Number of copies
    pages: '1-3,5',              // Pages to print (optional)
    scale: 'fit',                // 'fit' | 'noscale' | 'shrink'
    orientation: 'portrait',     // 'portrait' | 'landscape'
  };

  await printer.print(filePath, options);
  console.log(`Printed ${options.copies} copies to "${options.printer}"`);
}

printWithOptions('./pdfs/shipping-label.pdf').catch(console.error);
//:path=/static-assets/pdf/content-code-examples/nodejs/how-to/nodejs-print-pdf/custom-options.js
const printer = require('pdf-to-printer');

async function printWithOptions(filePath) {
  // List available printers to find the correct name
  const printers = await printer.getPrinters();
  printers.forEach((p) => {
    console.log(`${p.name} -- default: ${p.isDefault}`);
  });

  const options = {
    printer: 'HP LaserJet Pro',  // Exact name from getPrinters()
    copies: 2,                   // Number of copies
    pages: '1-3,5',              // Pages to print (optional)
    scale: 'fit',                // 'fit' | 'noscale' | 'shrink'
    orientation: 'portrait',     // 'portrait' | 'landscape'
  };

  await printer.print(filePath, options);
  console.log(`Printed ${options.copies} copies to "${options.printer}"`);
}

printWithOptions('./pdfs/shipping-label.pdf').catch(console.error);
JAVASCRIPT

Calling getPrinters() before print() serves two purposes: it confirms the printer is online and reachable, and it gives you the authoritative name string that the OS uses to route print jobs. Printer names often include version numbers or network suffixes that differ from display names shown in system settings.

TipsOn Windows, getPrinters() returns the printer list from the registry. On macOS/Linux, it queries CUPS. The isDefault flag identifies the printer that receives jobs when no printer name is specified.

What Printer Options Can Be Configured?

The printerOptions object supports the following fields:

pdf-to-printer option properties
OptionTypeDescriptionExample value
printerstringExact printer name as returned by getPrinters()'HP LaserJet Pro'
copiesnumberNumber of copies to print2
pagesstringPage range string'1-3,5'
scalestringPage scaling mode'fit', 'noscale', 'shrink'
orientationstringPage orientation override'portrait', 'landscape'

For documents that need custom paper sizes or a specific page orientation applied during PDF generation rather than at print time, configure those options on the IronPDF rendering step before saving the file.

How Can I Implement Batch Printing in Node.js?

Process a folder of PDF files or a dynamically generated list by iterating an array and calling printer.print() for each file. Using for...of with await keeps jobs sequential, which prevents the print spooler from being overwhelmed with simultaneous requests.

//:path=/static-assets/pdf/content-code-examples/nodejs/how-to/nodejs-print-pdf/batch-print.js
const printer = require('pdf-to-printer');
const fs = require('fs').promises;
const path = require('path');

class BatchPrinter {
  constructor(printerName = null) {
    this.printerName = printerName;
    this.queue = [];
  }

  async addFiles(filePaths) {
    for (const filePath of filePaths) {
      try {
        await fs.access(filePath);
        this.queue.push(filePath);
      } catch {
        console.warn(`Skipped (not found): ${filePath}`);
      }
    }
  }

  async printAll(options = {}) {
    const results = { successful: 0, failed: 0, errors: [] };

    for (const filePath of this.queue) {
      try {
        const printOptions = {
          ...options,
          ...(this.printerName && { printer: this.printerName }),
        };
        await printer.print(filePath, printOptions);
        results.successful++;
        console.log(`Printed: ${path.basename(filePath)}`);
      } catch (err) {
        results.failed++;
        results.errors.push({ file: filePath, error: err.message });
      }
    }

    this.queue = [];
    return results;
  }
}

// Usage: print monthly reports to a specific printer
(async () => {
  const batch = new BatchPrinter('Office Printer A3');

  await batch.addFiles([
    './reports/january.pdf',
    './reports/february.pdf',
    './reports/march.pdf',
  ]);

  const results = await batch.printAll({ copies: 1 });
  console.log(`Done -- ${results.successful} printed, ${results.failed} failed.`);
})();
//:path=/static-assets/pdf/content-code-examples/nodejs/how-to/nodejs-print-pdf/batch-print.js
const printer = require('pdf-to-printer');
const fs = require('fs').promises;
const path = require('path');

class BatchPrinter {
  constructor(printerName = null) {
    this.printerName = printerName;
    this.queue = [];
  }

  async addFiles(filePaths) {
    for (const filePath of filePaths) {
      try {
        await fs.access(filePath);
        this.queue.push(filePath);
      } catch {
        console.warn(`Skipped (not found): ${filePath}`);
      }
    }
  }

  async printAll(options = {}) {
    const results = { successful: 0, failed: 0, errors: [] };

    for (const filePath of this.queue) {
      try {
        const printOptions = {
          ...options,
          ...(this.printerName && { printer: this.printerName }),
        };
        await printer.print(filePath, printOptions);
        results.successful++;
        console.log(`Printed: ${path.basename(filePath)}`);
      } catch (err) {
        results.failed++;
        results.errors.push({ file: filePath, error: err.message });
      }
    }

    this.queue = [];
    return results;
  }
}

// Usage: print monthly reports to a specific printer
(async () => {
  const batch = new BatchPrinter('Office Printer A3');

  await batch.addFiles([
    './reports/january.pdf',
    './reports/february.pdf',
    './reports/march.pdf',
  ]);

  const results = await batch.printAll({ copies: 1 });
  console.log(`Done -- ${results.successful} printed, ${results.failed} failed.`);
})();
JAVASCRIPT

The BatchPrinter class separates validation from execution. Files that do not exist are skipped during addFiles() so that a single missing file does not abort the entire batch. The printAll() method records per-file errors and returns a summary that can be logged or forwarded to a monitoring service.

For dynamically generated reports, combine this pattern with IronPDF's HTML string to PDF conversion to generate and print in a single pipeline. The PDF compression example is worth applying before large print batches to reduce spooler transfer time on network printers.

TipsAdd a short await delay between jobs if the printer supports print queuing slowly -- some older network printers reject rapid successive submissions. A 200-500ms pause is usually sufficient.

What Are the Platform-Specific Considerations for Node.js PDF Printing?

The pdf-to-printer package uses different system commands on each OS. Understanding the underlying mechanism helps diagnose platform-specific failures.

How Does PDF Printing Work on Windows?

On Windows, pdf-to-printer shells out to SumatraPDF through a PowerShell command. SumatraPDF is bundled with the package -- no separate installation is needed. PowerShell script execution must be permitted under the current execution policy. Run Get-ExecutionPolicy in PowerShell to check; if the result is Restricted, set it to RemoteSigned or Bypass for the session.

Printer names on Windows are case-sensitive and must match the value shown in Settings > Bluetooth & devices > Printers & scanners exactly, including any parenthetical network suffix.

How Does PDF Printing Work on macOS and Linux?

On macOS and Linux, the package calls lp (part of CUPS). Confirm CUPS is running with lpstat -p -- this lists all registered printers and their current status. If no printers appear, the CUPS service may not be started; use sudo systemctl start cups on Linux or enable it via System Preferences > Printers on macOS.

The lp command does not support all of the same options as the Windows SumatraPDF path. The scale and orientation options may have no effect on CUPS-based printing depending on the printer driver. Test on the target hardware before deploying.

WarningThe pdf-to-printer package currently prints to local and network printers only. Cloud print services such as Microsoft Universal Print are not supported through this package.

How Do I Handle Security and Permissions When Printing PDFs?

Production printing systems that process sensitive documents -- contracts, financial records, medical forms -- need access controls and audit trails. Tracking who printed what and when is a compliance requirement in many regulated industries.

//:path=/static-assets/pdf/content-code-examples/nodejs/how-to/nodejs-print-pdf/secure-print.js
const printer = require('pdf-to-printer');
const crypto = require('crypto');

class AuditedPrinter {
  constructor() {
    this.log = [];
  }

  async print(filePath, userId, options = {}) {
    const jobId = crypto.randomBytes(8).toString('hex');
    const entry = { jobId, userId, filePath, options, status: 'pending', startedAt: new Date().toISOString() };
    this.log.push(entry);

    try {
      await printer.print(filePath, options);
      entry.status = 'completed';
      entry.completedAt = new Date().toISOString();
      return { success: true, jobId };
    } catch (err) {
      entry.status = 'failed';
      entry.error = err.message;
      throw err;
    }
  }

  getLog(userId = null) {
    return userId ? this.log.filter((e) => e.userId === userId) : this.log;
  }
}

// Usage
const auditedPrinter = new AuditedPrinter();

(async () => {
  await auditedPrinter.print('./contracts/nda-2026.pdf', 'user-42', { copies: 1 });
  console.log('Audit log:', auditedPrinter.getLog('user-42'));
})();
//:path=/static-assets/pdf/content-code-examples/nodejs/how-to/nodejs-print-pdf/secure-print.js
const printer = require('pdf-to-printer');
const crypto = require('crypto');

class AuditedPrinter {
  constructor() {
    this.log = [];
  }

  async print(filePath, userId, options = {}) {
    const jobId = crypto.randomBytes(8).toString('hex');
    const entry = { jobId, userId, filePath, options, status: 'pending', startedAt: new Date().toISOString() };
    this.log.push(entry);

    try {
      await printer.print(filePath, options);
      entry.status = 'completed';
      entry.completedAt = new Date().toISOString();
      return { success: true, jobId };
    } catch (err) {
      entry.status = 'failed';
      entry.error = err.message;
      throw err;
    }
  }

  getLog(userId = null) {
    return userId ? this.log.filter((e) => e.userId === userId) : this.log;
  }
}

// Usage
const auditedPrinter = new AuditedPrinter();

(async () => {
  await auditedPrinter.print('./contracts/nda-2026.pdf', 'user-42', { copies: 1 });
  console.log('Audit log:', auditedPrinter.getLog('user-42'));
})();
JAVASCRIPT

The AuditedPrinter class assigns a unique job ID to every print request and records user identity, file path, and timestamps. Persisting this.log to a database or append-only log file turns this into a durable audit record. For documents that contain personally identifiable information, consider using IronPDF's PDF encryption features to protect files at rest before they reach the printer queue.

For server applications that accept print requests over HTTP, validate file type and size before printing -- reject any upload that is not a valid PDF binary. Never pass user-supplied file paths directly to printer.print() without sanitization.

ImportantStore audit logs outside the application's writable directory. An attacker with file system write access should not be able to tamper with print records.

What Are the Next Steps for Node.js PDF Printing?

This guide covered printing existing PDF files to local and network printers using pdf-to-printer, from basic single-file printing to batch queues, custom printer options, platform considerations, and audit logging for regulated environments.

To extend this workflow with PDF generation, start a free trial of IronPDF for Node.js and follow the HTML to PDF tutorial to build an end-to-end document pipeline. For licensing options and volume pricing, see the IronPDF licensing page.

Ready to go further? Explore the full IronPDF for Node.js how-to collection to learn how to merge PDF files, compress PDF files, and convert PDFs to images.

Frequently Asked Questions

What is the easiest way to print PDF files in Node.js?

Use the pdf-to-printer npm package. Install it with npm install pdf-to-printer, then call printer.print('./file.pdf') -- it returns a Promise and queues the job with the system default printer in a single call.

What are the prerequisites for printing PDFs in Node.js?

Node.js 14.x or higher, npm, and a configured printer driver on the host machine. On Windows, PowerShell execution policy must permit script execution. On macOS and Linux, CUPS must be installed and running, with at least one printer registered via lpstat -p.

How do I print to a specific printer in Node.js?

Pass a printerOptions object as the second argument to printer.print(). Set the printer field to the exact printer name returned by printer.getPrinters(). Printer names are case-sensitive and must match the OS registry entry exactly.

Can I generate a PDF and then print it in the same Node.js script?

Yes. Use IronPDF for Node.js to generate the file first: call PdfDocument.fromHtml(html) to render HTML content, save it with pdf.saveAs(path), then pass that path to printer.print(path). Install IronPDF with npm install @ironsoftware/ironpdf.

Does pdf-to-printer work on macOS and Linux?

Yes. On macOS and Linux, the package delegates to the lp command from CUPS. Confirm CUPS is running with lpstat -p. Note that the scale and orientation options may not take effect on all CUPS printer drivers.

How do I add an audit log for print jobs in Node.js?

Wrap printer.print() in a class that assigns a unique job ID using crypto.randomBytes(8).toString('hex') and records the file path, user ID, and timestamps. Persist the log array to a database or append-only file outside the application's writable directory.

Darrius Serrant
Full Stack Software Engineer (WebOps)

Darrius Serrant holds a Bachelor’s degree in Computer Science from the University of Miami and works as a Full Stack WebOps Marketing Engineer at Iron Software. Drawn to coding from a young age, he saw computing as both mysterious and accessible, making it the perfect medium for creativity ...

Read More
Ready to Get Started?
Version: 2026.4 just released
Still Scrolling Icon

Still Scrolling?

Want proof fast?
run a sample watch your HTML become a PDF.