Skip to content
KibouAkariPublic

About

S-PDF is a fast, self-hosted, open-source PDF toolkit - merge, split, convert, watermark, compress, and visually edit PDFs from a clean web UI, with no subscriptions or third-party uploads.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

S-PDF logo

S-PDF

Merge, convert, edit, and clean up your PDFs - fast, free, and self-hosted.

CI Project source: MIT

A fast, self-hosted, open-source alternative to Adobe Acrobat / iLovePDF. Merge, split, convert, watermark, compress and visually edit PDFs from a clean, modern web UI - no subscriptions, no watermarked exports, no uploads to a third party.

Stack

Layer Tech
Frontend React + TypeScript + Vite + Tailwind CSS v4, pdf.js (rendering), fabric.js (visual editor), dnd-kit (drag-to-reorder)
API Node.js + Express + TypeScript, pdf-lib for in-process PDF manipulation (used for local dev / Docker)
Converter Python + FastAPI, PyMuPDF (page ops, rasterization, compression), pdf2docx (PDF→Word), LibreOffice headless (Word→PDF)

Many classic PDF operations are implemented twice: once in Node (apps/api, via pdf-lib) for local development and Docker deployments, and once in Python (services/converter, via PyMuPDF). Native editing of original PDF elements is implemented in Python only; the Node API forwards those requests to the converter. This also allows a two-service (web + converter) deployment on platforms like Vercel that don't run a long-lived Node API. See CONTRIBUTING.md for what that means when you change a PDF endpoint.

S-PDF can be self-hosted. Many PDF operations use in-memory buffers, while some conversions write temporary files that are cleaned up after the operation. Review your deployment, logs, temporary storage and resource limits before processing sensitive documents.

Engineering documentation

Editor status: Native editing is experimental: text spans, embedded raster images and simple line/rectangle paths can be moved, changed or removed. The editor displays the PDF as a dedicated read-only page layer with transparent controls above it, and groups editing tools into a compact toolbar. Complex vector graphics, OCR text and lossless layout editing are not supported. See the native editing guide and test matrix.

Features

  • Merge & Organize - combine multiple PDFs, drag pages into any order, rotate or delete pages, export as one file.
  • Split - extract page ranges into separate PDFs (returned as a ZIP).
  • Edit PDF (experimental) - select and change existing PDF text spans and embedded images, move and resize selections, and add text, images, shapes or freehand highlights. Native changes use the Python converter and may not preserve complex formatting. Scanned text requires OCR, which is not yet included.
  • PDF ⇄ Word - pdf2docx for PDF→Word; LibreOffice headless for Word→PDF.
  • PDF ⇄ Images - rasterize pages to PNG at a chosen DPI, or build a PDF from a set of images.
  • Watermark - centered or tiled text watermark with color/opacity/rotation controls.
  • Page numbers - configurable position, start number and format string.
  • Compress - re-encodes oversized embedded images and rebuilds the PDF object structure.

Getting started (local dev)

Prerequisites: Node.js 22.13+ (or Node.js 24+), Python 3.11+, and LibreOffice for Word→PDF. Python commands below expect python to be available.

Install dependencies in the repository root. Use a Python virtual environment so the converter packages do not modify your global Python installation.

On macOS or Linux:

npm install --workspaces
python -m venv .venv
source .venv/bin/activate
npm run converter:install
cp apps/api/.env.example apps/api/.env

On Windows PowerShell:

npm install --workspaces
python -m venv .venv
.venv\Scripts\Activate.ps1
npm run converter:install
Copy-Item apps/api/.env.example apps/api/.env

In the first terminal, activate the virtual environment and start npm run converter:dev. In another terminal, start npm run dev for the frontend and Node API. The Python service must be available for selecting or changing existing PDF content.

Docker

docker compose up --build

Serves the web app on http://localhost:8080, proxying /api to the Node service, which in turn talks to the Python converter service. The converter image bundles LibreOffice so Word→PDF works out of the box in Docker.

Deploying to Vercel

This repo includes a root vercel.json that defines two services and routes all /api/* traffic straight to the Python converter service (there is no Node API in this deployment path):

{
  "services": {
    "web": {
      "root": "apps/web",
      "framework": "vite",
      "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
    },
    "converter": { "root": "services/converter", "entrypoint": "main:app" }
  },
  "rewrites": [
    { "source": "/api(/.*)?", "destination": { "type": "service", "service": "converter" } },
    { "source": "/(.*)", "destination": { "type": "service", "service": "web" } }
  ]
}
  • This uses Vercel's Services feature (not classic zero-config Functions), so the Python service needs an explicit entrypoint: "main:app" pointing at the FastAPI app object in services/converter/main.py - there's no api/ folder involved.
  • The web service's own rewrites fall back every path to /index.html. Without this, visiting a client-side route directly (e.g. /tools/organize, or any unknown path meant to hit the custom 404 page) returns Vercel's generic static 404 instead of the React app, since the static file for that path doesn't actually exist on disk.
  • Import the repo into Vercel as a single project; it will pick up both services from vercel.json automatically.
  • Known limitation: Word→PDF needs LibreOffice, which isn't available in Vercel's serverless Python runtime - that endpoint will return a clear 503 there. It works fully in Docker/self-hosted deployments (see below).
  • Known risk: pdf2docx pulls in opencv-python-headless + numpy, which can push the function bundle close to Vercel's size limits. If a deploy fails on size, that's the first place to look.

Project layout

apps/
  web/      React frontend (Vite)
  api/      Express API - pdf-lib based; used for local dev & Docker
services/
  converter/  FastAPI microservice - full PDF API (PyMuPDF) + pdf2docx / LibreOffice conversions
    main.py     entrypoint referenced by vercel.json as "main:app"

Notes & limitations

  • Word→PDF requires LibreOffice (soffice) installed on the machine running the converter service (bundled automatically in the Docker image; not available on Vercel).
  • The visual editor can reconstruct selected native text, raster images, and simple line/rectangle paths with PyMuPDF. Changes remove the selected original content where supported. Layout may change. A white overlay rectangle is not a secure redaction, and S-PDF has no security-verified privacy-redaction workflow.
  • Original document fonts, complex graphics, scanned text, form fields, and annotation round-trips are not preserved by arbitrary changes. See Native Editing.

Contributing

Contributions are welcome! Please read CONTRIBUTING.md for local setup, coding conventions, and what to check before opening a PR. This project follows the Code of Conduct.

Found a security issue? Please see SECURITY.md instead of opening a public issue.

Licensing

S-PDF's own source is under MIT. The complete installed application includes separate dependency licenses. PyMuPDF/MuPDF is AGPLv3 or commercially licensed, and deploying or redistributing an integrated solution requires an appropriate licensing review. See Licensing and third-party obligations.

About

S-PDF is a fast, self-hosted, open-source PDF toolkit - merge, split, convert, watermark, compress, and visually edit PDFs from a clean web UI, with no subscriptions or third-party uploads.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages