Reordering PDF pages means changing the sequence of pages in a document without altering the content. It is a common task when assembling reports, correcting scanned documents, or reorganizing slide decks. This guide covers the free browser-based method, programmatic approaches in JavaScript and Python, and how to handle edge cases like links and bookmarks.
How to reorder PDF pages online (free, no upload)
The fastest way to rearrange PDF pages is PDF4.dev's free Reorder PDF tool. Open the tool, drop your PDF, drag the page thumbnails into the order you want, and download the result. The whole process runs in your browser using pdf-lib — your file never reaches a server.
Steps:
- Open pdf4.dev/tools/reorder-pdf
- Drop your PDF onto the upload area or click to browse
- Drag the page thumbnails into the new order
- Click Download reordered PDF
No account is required. The tool handles multi-page PDFs up to several hundred pages. For large files, loading thumbnails may take a few seconds as the browser renders each page from the PDF's vector data.
Reorder PDF pages with JavaScript (pdf-lib)
pdf-lib is a pure JavaScript library for creating and modifying PDFs in Node.js and browsers. It does not shell out to Chromium or require a server — all processing happens in memory.
To reorder pages, copy all pages from the source document, create a new document, and add pages in the desired sequence:
import { PDFDocument } from "pdf-lib";
import { readFileSync, writeFileSync } from "fs";
async function reorderPages(
inputPath: string,
newOrder: number[], // 0-based page indices in desired order
outputPath: string
): Promise<void> {
const pdfBytes = readFileSync(inputPath);
const srcDoc = await PDFDocument.load(pdfBytes);
const dstDoc = await PDFDocument.create();
const copiedPages = await dstDoc.copyPages(srcDoc, newOrder);
for (const page of copiedPages) {
dstDoc.addPage(page);
}
const newPdfBytes = await dstDoc.save();
writeFileSync(outputPath, newPdfBytes);
}
// Move page 3 to the front: [2, 0, 1, 3, 4, ...]
await reorderPages("input.pdf", [2, 0, 1, 3, 4], "output.pdf");The copyPages method accepts an array of 0-based page indices in any order. Passing [2, 0, 1] copies page 3 first, then page 1, then page 2. Repeated indices are allowed, which means you can duplicate pages in the same call.
Generating the newOrder array programmatically
For systematic reordering, calculate the index array rather than hardcoding it:
import { PDFDocument } from "pdf-lib";
import { readFileSync, writeFileSync } from "fs";
async function reversePages(inputPath: string, outputPath: string) {
const pdfBytes = readFileSync(inputPath);
const srcDoc = await PDFDocument.load(pdfBytes);
const pageCount = srcDoc.getPageCount();
// Reverse order: [n-1, n-2, ..., 1, 0]
const reversedOrder = Array.from({ length: pageCount }, (_, i) => pageCount - 1 - i);
const dstDoc = await PDFDocument.create();
const pages = await dstDoc.copyPages(srcDoc, reversedOrder);
for (const page of pages) dstDoc.addPage(page);
writeFileSync(outputPath, await dstDoc.save());
}
// Move one page: swap pages at index a and b
function swapPages(order: number[], a: number, b: number): number[] {
const newOrder = [...order];
[newOrder[a], newOrder[b]] = [newOrder[b], newOrder[a]];
return newOrder;
}Reorder PDF pages with Python (PyPDF)
PyPDF (formerly PyPDF2) is the standard Python library for PDF manipulation. It handles page reordering with a reader/writer pattern:
from pypdf import PdfReader, PdfWriter
def reorder_pages(input_path: str, new_order: list[int], output_path: str) -> None:
"""
new_order: list of 0-based page indices in desired sequence.
Example: [2, 0, 1] moves page 3 to the front.
"""
reader = PdfReader(input_path)
writer = PdfWriter()
for page_index in new_order:
writer.add_page(reader.pages[page_index])
with open(output_path, "wb") as f:
writer.write(f)
# Reverse all pages
page_count = PdfReader("input.pdf").get_num_pages()
reorder_pages("input.pdf", list(range(page_count - 1, -1, -1)), "reversed.pdf")PyMuPDF (fitz) offers the most concise API: doc.select(indices) reorders, duplicates, or removes pages in one call. It is also the fastest Python PDF library for most operations, running roughly 5-10x faster than pypdf on large documents.
Comparison: Python PDF libraries for page reordering
| Library | Install | API style | Speed (100 pages) | Handles encrypted PDFs |
|---|---|---|---|---|
| PyPDF | pip install pypdf | reader/writer | ~200ms | Yes (with password) |
| PyMuPDF | pip install pymupdf | document.select() | ~30ms | Yes (with password) |
| pdfminer.six | pip install pdfminer.six | low-level | Not designed for manipulation | No |
For page reordering, PyMuPDF is the fastest option. PyPDF is a lighter dependency if PyMuPDF's binary size is a concern.
Reorder PDF pages in a web app (React + pdf-lib)
For a drag-and-drop reorder UI, combine pdfjs-dist for thumbnail rendering with pdf-lib for the actual reordering:
import { useState, useEffect } from "react";
import { PDFDocument } from "pdf-lib";
import * as pdfjs from "pdfjs-dist";
pdfjs.GlobalWorkerOptions.workerSrc = "/pdf.worker.min.js";
interface PageThumb {
index: number;
dataUrl: string;
}
export function PdfReorder({ file }: { file: File }) {
const [thumbs, setThumbs] = useState<PageThumb[]>([]);
const [order, setOrder] = useState<number[]>([]);
useEffect(() => {
(async () => {
const buffer = await file.arrayBuffer();
const pdf = await pdfjs.getDocument({ data: buffer }).promise;
const pages: PageThumb[] = [];
for (let i = 1; i <= pdf.numPages; i++) {
const page = await pdf.getPage(i);
const viewport = page.getViewport({ scale: 0.3 });
const canvas = document.createElement("canvas");
canvas.width = viewport.width;
canvas.height = viewport.height;
await page.render({ canvasContext: canvas.getContext("2d")!, viewport }).promise;
pages.push({ index: i - 1, dataUrl: canvas.toDataURL() });
}
setThumbs(pages);
setOrder(pages.map((p) => p.index));
})();
}, [file]);
async function handleDownload() {
const pdfBytes = await file.arrayBuffer();
const srcDoc = await PDFDocument.load(pdfBytes);
const dstDoc = await PDFDocument.create();
const copied = await dstDoc.copyPages(srcDoc, order);
for (const page of copied) dstDoc.addPage(page);
const blob = new Blob([await dstDoc.save()], { type: "application/pdf" });
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = "reordered.pdf";
a.click();
}
// Swap positions on drag-and-drop (simplified)
function moveThumb(fromIndex: number, toIndex: number) {
const newOrder = [...order];
const [moved] = newOrder.splice(fromIndex, 1);
newOrder.splice(toIndex, 0, moved);
setOrder(newOrder);
}
return (
<div>
<div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
{order.map((pageIndex, position) => (
<img
key={pageIndex}
src={thumbs[pageIndex]?.dataUrl}
alt={`Page ${pageIndex + 1}`}
draggable
onDragOver={(e) => e.preventDefault()}
onDrop={() => moveThumb(thumbs.findIndex((t) => t.dataUrl === thumbs[pageIndex].dataUrl), position)}
style={{ width: 80, cursor: "grab", border: "1px solid #ccc" }}
/>
))}
</div>
<button onClick={handleDownload}>Download reordered PDF</button>
</div>
);
}This pattern (pdfjs for thumbnails + pdf-lib for manipulation) is exactly how PDF4.dev's Reorder PDF tool works. The key insight: pdfjs renders pages to canvas for preview, while pdf-lib handles the actual file modification — the two libraries complement each other.
How page reordering works inside a PDF
A PDF file stores pages as independent objects with their own resource dictionaries. The document's page tree (a /Pages node in the PDF cross-reference table) lists pages in display order. Reordering updates the page tree references, not the page content objects themselves.
This is why reordering is fast and lossless. The content streams (text, images, vector graphics) are not touched — only the order in which they appear in the page tree changes. A typical 10-page reorder operation produces a file nearly identical in size to the original.
One side effect: the original page objects may remain in the PDF's cross-reference table even if they're no longer referenced (orphaned objects). Running the output through a PDF linearizer or compressor removes these. PDF4.dev's Compress PDF tool can clean up orphaned objects as part of compression.
Edge cases and gotchas
Internal links after reordering
PDFs store internal links as /GoTo actions that reference a page by its page object number or by index. After reordering, a link that previously pointed to "page 3" may now point to the wrong page.
To audit internal links after reordering, open the PDF in a reader and test every bookmark or cross-reference. If you control the source HTML for programmatic PDF generation (via PDF4.dev's API), the cleaner approach is to generate the PDF with links intact after establishing the final page order.
Bookmarks (outlines)
PDF bookmarks (the outline panel in PDF viewers) reference specific pages. After reordering, bookmarks may point to incorrect pages. PyMuPDF provides doc.get_toc() and doc.set_toc() for reading and rewriting the table of contents after reordering, which lets you remap bookmarks to their new positions.
Encrypted and permission-restricted PDFs
PDFs can have two types of passwords: a user password (required to open the file) and an owner password (required to edit it). Reordering pages is an editing operation. If the PDF's permissions restrict page manipulation, you need the owner password to proceed.
Remove restrictions first using PDF4.dev's free tools, then reorder pages. See our guide on how to remove a password from a PDF for the full workflow.
Very large PDFs (500+ pages)
Browser-based reordering loads all pages into memory for thumbnail rendering. For PDFs over 300-400 pages, a Node.js or Python script is more reliable. Both pdf-lib and PyMuPDF handle large files by streaming page data rather than loading all content at once:
import fitz
# fitz.open() is lazy — pages are loaded on access, not all at once
doc = fitz.open("large-document.pdf")
# select() builds the new page list without rendering thumbnails
new_order = list(range(doc.page_count - 1, -1, -1)) # reverse
doc.select(new_order)
doc.save("output.pdf", garbage=3, deflate=True) # garbage=3 removes orphaned objectsThe garbage=3 option in PyMuPDF removes unreferenced objects from the output file, equivalent to running a PDF linearizer pass. This is useful after any restructuring operation.
Comparison: tools and methods for reordering PDF pages
| Method | Best for | Effort | File privacy | Cost |
|---|---|---|---|---|
| PDF4.dev Reorder PDF | Quick one-off, any file | None | File stays in browser | Free |
| Adobe Acrobat | Professional workflows | Medium | Cloud or local | Paid |
| pdf-lib (JavaScript) | Web apps, automation | Low code | Your infrastructure | Free (library) |
| PyMuPDF (Python) | Batch processing, large PDFs | Low code | Your infrastructure | Free (library) |
| PyPDF (Python) | Simple scripts | Low code | Your infrastructure | Free (library) |
For most users, the Reorder PDF tool is the fastest path. For batch reordering (hundreds of PDFs) or integration into an existing workflow, PyMuPDF's doc.select() is the most concise programmatic option.
Combine reorder with split and merge for complex workflows
Reordering is often one step in a larger document assembly workflow. Common patterns:
Assemble a report from multiple sources:
- Split each source PDF into individual pages
- Collect the pages you need in the desired order
- Merge them into the final document
Correct a scanned document:
- Open the scanned PDF in the Reorder PDF tool
- Drag pages into the correct sequence
- Download the corrected document
Remove specific pages then reorder the remainder:
- Use Delete Pages to remove unwanted pages
- Reorder the remaining pages in the Reorder PDF tool
For programmatic workflows combining these operations, see our guides on how to split a PDF into individual pages and how to merge PDF files.
Summary
Reordering PDF pages is a lossless operation that changes page sequence without altering content quality. Use PDF4.dev's free Reorder PDF tool for quick visual reordering in your browser. For programmatic use:
- JavaScript: pdf-lib with
copyPages()andaddPage()in any order - Python: PyMuPDF's
doc.select(indices)is the fastest single-call API; PyPDF's reader/writer pattern is the standard alternative
Watch for internal links and bookmarks after reordering — they reference pages by index and may need to be remapped. For large files over a few hundred pages, prefer a server-side script over browser-based tools.
Start generating PDFs
Build PDF templates with a visual editor. Render them via API from any language in ~300ms.