PaperJSX generates PowerPoint files from JSON inside Express route handlers with zero native dependencies. Install the package, add a POST route, accept a JSON body, call generate(), and return the buffer with PPTX MIME headers. The complete API endpoint is 15 lines of code.
1. Install
This guide is Express-specific. Not on Express? See the framework-agnostic hub, generate PPTX from any data source, or the Google Sheets to PPTX walkthrough.
npm install express @paperjsx/json-to-pptx
Two packages. No postinstall scripts, no native compilation. PaperJSX has zero native dependencies — it runs anywhere Express runs, including Docker containers, PM2 clusters, and traditional VPS deployments.
2. Minimal Express route
import express from "express";
import { generate } from "@paperjsx/json-to-pptx";
const app = express();
app.use(express.json());
app.post("/api/pptx", async (req, res) => {
try {
const buffer = await generate(req.body);
res.set({
"Content-Type":
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
"Content-Disposition": 'attachment; filename="report.pptx"',
});
res.send(buffer);
} catch (err) {
res.status(400).json({ error: err.message });
}
});
app.listen(3000, () => console.log("Listening on :3000"));
Test it with curl:
curl -X POST http://localhost:3000/api/pptx \
-H "Content-Type: application/json" \
-d '{"slides":[{"elements":[{"type":"text","value":"Hello from Express","style":{"fontSize":36,"bold":true}}]}]}' \
-o test.pptx
Open test.pptx in PowerPoint, Keynote, or Google Slides. The file is valid OOXML — no repair dialog, no corruption.
How do you add charts and tables?
The JSON body can include any element type PaperJSX supports. Here is a request body that produces a slide with a bar chart and a data table.
{
"slides": [
{
"elements": [
{
"type": "text",
"value": "Q3 revenue by region",
"style": { "fontSize": 28, "bold": true }
},
{
"type": "chart",
"chartType": "bar",
"data": {
"categories": ["NA", "EMEA", "APAC"],
"series": [
{ "name": "Revenue", "values": [4200, 3100, 2800] }
]
}
},
{
"type": "table",
"headers": ["Region", "Revenue", "Growth"],
"rows": [
["NA", "$4.2M", "+10%"],
["EMEA", "$3.1M", "+7%"],
["APAC", "$2.8M", "+27%"]
]
}
]
}
]
}
The chart is native and editable — recipients can click it in PowerPoint and modify the data. For combo charts (bar + line on the same axis), set "chartType": "combo" and add a "type" field per series. Extended features across all four formats require Pro ($199/mo). For the supported schema, see the PPTX documentation.
How do you generate from database data?
In production, PPTX schemas are assembled from database queries — not hardcoded JSON. Here is a route that generates a multi-slide deck from a list of regions stored in a database.
import { db } from "./db.mjs";
app.get("/api/report", async (req, res) => {
const regions = await db.query("SELECT * FROM regions");
const doc = {
slides: [
// title slide
{
elements: [
{ type: "text", value: "Q3 report",
style: { fontSize: 36, bold: true } }
]
},
// one slide per region
...regions.map(r => ({
elements: [
{ type: "text", value: r.name,
style: { fontSize: 24, bold: true } },
{
type: "chart",
chartType: "bar",
data: {
categories: ["Q1", "Q2", "Q3"],
series: [{ name: "Revenue", values: r.quarterly }]
}
}
]
}))
]
};
const buffer = await generate(doc);
res.set({
"Content-Type": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
"Content-Disposition": 'attachment; filename="q3-report.pptx"',
});
res.send(buffer);
});
How do you add PDF, DOCX, and XLSX?
The same JSON body can produce any of PaperJSX's four output formats. Add a format query parameter and switch the generator. This is the same pattern used in the multi-format tutorial and the Next.js PDF tutorial.
import { generate as toPptx } from "@paperjsx/json-to-pptx";
import { generate as toDocx } from "@paperjsx/json-to-docx";
import { generate as toPdf } from "@paperjsx/json-to-pdf";
import { generate as toXlsx } from "@paperjsx/json-to-xlsx";
const formats = {
pptx: { fn: toPptx, mime: "application/vnd.openxmlformats-officedocument.presentationml.presentation" },
docx: { fn: toDocx, mime: "application/vnd.openxmlformats-officedocument.wordprocessingml.document" },
pdf: { fn: toPdf, mime: "application/pdf" },
xlsx: { fn: toXlsx, mime: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" },
};
app.post("/api/generate", async (req, res) => {
const format = req.query.format || "pptx";
const gen = formats[format];
if (!gen) return res.status(400).json({ error: "Invalid format" });
const buffer = await gen.fn(req.body);
res.set({
"Content-Type": gen.mime,
"Content-Disposition": `attachment; filename="report.${format}"`,
});
res.send(buffer);
});
The client calls POST /api/generate?format=pdf with the same JSON body to get a PDF. One codebase, one data structure, four output formats.
Production considerations
| Concern | Recommendation |
|---|---|
| Request body size | Increase Express's JSON limit for schemas with base64 images: app.use(express.json({ limit: '10mb' }))
|
| Timeout | A 10-slide deck generates in ~200ms. Set req.setTimeout(30000) only for very large documents with many embedded images. |
| Concurrency |
generate() is CPU-bound and stateless. Use PM2 cluster mode or Node.js cluster module to utilize multiple cores. |
| Input validation | Validate the JSON schema before passing to generate(). At minimum: verify slides is a non-empty array and each element has a type field. |
| Error handling | Wrap generate() in try/catch. Invalid schemas throw descriptive errors. Return 400 with the error message. |
| Authentication | Document generation endpoints should be authenticated. Use your existing Express auth middleware (JWT, session, API key). |
Start generating PPTX in Express — read the quick start, explore the PPTX reference, or see the hosted API quick start.
Top comments (0)