How to Use a PDF Generation SDK With Next.js

By Kevin Herschbach | 2026 Jan 16

Sanity Image
Read time

13 min

PDF generation is one of the most common requirements in modern web applications. From invoices and reports to certificates and legal documents, businesses need reliable ways to create professional PDFs on demand.

Next.js makes an excellent foundation for building PDF generation services thanks to its API routes and server-side capabilities, but choosing the right PDF SDK can mean the difference between a fragile solution that breaks on edge cases and a production-ready system that scales with your needs.

In this tutorial, you'll learn how to generate PDFs in your Next.js app. To achieve this, you'll define an API route that uses the Apryse Server SDK for PDF generation. You'll then implement image file to PDF conversion as an example of what else is possible.

To build your Next.js PDF generator, you'll follow these steps:

  1. Set up the Next.js project
  2. Install the Apryse SDK
  3. Set up basic styling
  4. Create the PDF generation API route
  5. Build the frontend
  6. Implement image file to PDF conversion

Prerequisites

Copied to clipboard

Before you begin, make sure a recent LTS version of Node.js is installed on your machine.

At the time of writing, the current version of the Apryse SDK is v11.8.0, which is compatible with Node.js versions up to v24.x.

To check your currently installed version, run node --version.

Step 1: Set Up Your Next.js Project

Copied to clipboard

In your project directory (we'll go with nextjs-pdf-generation-app in this example), start by initializing npm.

npm init -y

This creates a package.json file.

Next, install Next.js and React ...

npm install next@14.2.35 react@18 react-dom@18

... as well as TypeScript and the corresponding type definitions.

npm install --save-dev typescript @types/react @types/react-dom @types/node

Create a file named tsconfig.json in your project root with the following content to configure TypeScript behavior for your Next.js project:

Then open package.json and add the necessary Next.js scripts:

Step 2: Install the Apryse SDK

Copied to clipboard

Now, install the server-side Apryse SDK (formerly PDFTron, hence the package name), which you'll use to generate PDF files.

npm install @pdftron/pdfnet-node

Since the Apryse SDK uses native Node.js modules that need special configuration, create a file named next.config.js in your project root with the following content:

This tells Next.js not to bundle the Apryse SDK, since its native modules must run in Node.js.

Step 3: Set Up Basic Styling

Copied to clipboard

For your UI, add some CSS by creating a new directory app in your project root and a new file app/globals.css with the following content:

Step 4: Create the PDF Generation API Route

Copied to clipboard

Now you'll create the API that generates PDFs. To use the Apryse SDK for this, you'll need a license key, which you can generate for free in the Apryse SDK documentation.

For easy access to your license key, create a file .env.local in your project root with the following line, replacing your_license_key with your actual key:

APRYSE_LICENSE_KEY=your_license_key

Next, create a new directory app/api/generate-pdf and a new file app/api/generate-pdf/route.ts with the following code:

Let's break this down.

const { PDFNet } = await import('@pdftron/pdfnet-node');
  • Loads the Apryse SDK only when needed
  • Required for native modules in Next.js
await PDFNet.initialize(process.env.APRYSE_LICENSE_KEY);
  • Starts up the Apryse engine
  • Uses the license key you stored in the .env.local file
const doc = await PDFNet.PDFDoc.create();
  • Creates an empty PDF in memory
  • Defines page dimensions of 612 x 792 points, which corresponds to 8.5" x 11" (1 inch equals 72 points in PDFs)
doc.pagePushBack(page);
  • Adds the page to the document
  • Saves the PDF to memory (not the disk)
  • Returns the PDF as downloadable file

Step 5: Build the Frontend

Copied to clipboard

With the API route completed, it's time to build the user interface for your Next.js app.

First, create a new file app/layout.tsx for your root layout.

Then create a new file app/page.tsx for your app's homepage.

Some notes about this page.tsx:

'use client';
  • Marks this as a Client Component
  • Required for interactive features like onClick
const response = await fetch('/api/generate-pdf');
  • Calls the API route you created earlier
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
  • Converts the PDF data to a downloadable blob
  • Creates a temporary URL for the blob
const link = document.createElement('a');
link.href = url;
link.download = 'empty.pdf';
link.click();
  • Creates an invisible link
  • Sets the filename
  • Triggers the download programmatically
window.URL.revokeObjectURL(url);
document.body.removeChild(link);
  • Removes the temporary URL from memory
  • Removes the link element

Checkpoint: Test the Minimal Implementation

Copied to clipboard

At this point, you have a Next.js app that will generate an empty PDF when the user clicks on the "Generate PDF" button and triggers a download. In the next steps, you'll implement the data upload that makes this actually useful.

For now, just run the app to see if everything is working as intended.

npm run dev

If PDF generation fails, check your IDE's console (not the browser's) for issues like a missing license key.

Step 6: Implement Image File to PDF Conversion

Copied to clipboard

The Apryse SDK supports PDF generation from a wide range of data sources, including from templates and by converting various file formats.

In this example, you'll implement image file to PDF conversion, which requires much more infrastructure for file handling, user feedback, error cases, and state management. Nonetheless, you can use the current state of your app as a basis.

First, you need to change the API route.

Open app/api/generate-pdf/route.ts and replace the code with the following:

Here's an overview of the most important changes to route.ts:

  • The HTTP request method changed from GET to POST to accept file uploads.
  • The API route now handles FormData instead of accepting no input at all.
  • The implementation now works with temporary files on the filesystem instead of keeping everything in memory.
  • The code now uses Apryse's high-level Convert API instead of manually creating PDF pages and elements.

Note that this is still a minimal implementation and not meant for deployment. When building your own production-ready app, consider adding file size limits, more robust MIME type checking, and sanitization of filenames for the output. Also keep in mind what happens if the license key is invalid, how to handle timeouts for large files, and how to manage memory for large uploads.

With the API route updated, you need to adjust the frontend. Open app/page.tsx and replace its content with the following code:

These are the most important changes to page.tsx:

  • The component now uses React state to track the file, loading status, and preview instead of being completely static.
  • The UI now includes a complete form with file input, preview, file info, and a button instead of just a single button.
  • The code now creates FormData and sends a POST request to upload files instead of making a simple GET request.

And that's it! You can now use your Next.js app to upload an image and convert it to a PDF.

Run npm run dev to test your creation.

Where to Go From Here

Copied to clipboard

Converting image files is a comparatively straightforward way to generate PDFs. With the Apryse SDK, you can go much further, e.g., with templates that the SDK uses to create fully formatted PDF documents. Other features include PDF manipulation, true redaction, and smart data extraction.

When deploying a Next.js application such as this one, carefully consider your runtime environment. Native bindings only work in a full Node.js environment, not in serverless edge runtimes, and your API route creates temporary files that require filesystem access. Additionally, image to PDF conversion can take several seconds for large files, which may exceed the timeout limits of some serverless platforms.

When it comes to deployment approaches, serverless functions are the easiest option for Next.js applications, but traditional long-running Node.js servers offer better reliability with no cold starts, no timeout restrictions, and are more cost-effective at scale. Container-based deployments provide maximum portability and control and minimize cold start delays compared to traditional serverless functions.

To explore more of what the Apryse SDK has to offer, check out its documentation and the various samples. Start your free trial and contact our sales team to get started.

Sanity Image

Kevin Herschbach

Technical Content Writer

Share this post

email
linkedIn
twitter