Generating PDF invoices on the backend is a common need for many web applications. In this guide, we’ll build a simple way to create PDF invoices using React components with @react-pdf/renderer
— but in a Node.js backend environment.
Even if you’re a beginner, this step-by-step explanation will help you understand how to create, render, and send PDFs from your backend server.
Why Use React for PDF Generation?
You might be wondering:
Why would I use React — a frontend UI library — in a Node.js backend?
Good question! Here’s the simple answer:
-
@react-pdf/renderer
lets you build PDFs using React components — just like building a UI. - This means you describe your invoice as reusable React components with JSX syntax.
- React helps structure your PDF content clearly and makes it easy to maintain and update.
- Because
@react-pdf/renderer
uses React components internally, you need to havereact
andreact-dom
installed for it to work correctly.
Why Do We Need react
and react-dom
in Backend?
- Even though you’re not building a frontend app,
@react-pdf/renderer
uses React’s core features to interpret your components and JSX. -
react
is the core library that understands React components. -
react-dom
is often used for DOM-related rendering, and some internal parts of@react-pdf/renderer
depend on it, so it must be installed as well. - You won’t be using
react-dom
to render HTML or web pages here — it’s just a required dependency for@react-pdf/renderer
.
Step 1: Set Up Your Project and Install Packages
Create a new Node.js project if you don’t have one yet:
mkdir invoice-generator
cd invoice-generator
npm init -y
Install Express (to create the backend API), @react-pdf/renderer
for PDF generation, and React dependencies:
npm install express @react-pdf/renderer react react-dom
Step 2: Create a React PDF Invoice Template
Create a file named Invoice.js
for your invoice React component.
// Invoice.js
import React from "react";
import { Document, Page, Text, View, StyleSheet } from "@react-pdf/renderer";
const styles = StyleSheet.create({
page: { padding: 30 },
section: { marginBottom: 10 },
});
const Invoice = ({ order }) => (
<Document>
<Page style={styles.page}>
<View style={styles.section}>
<Text>Invoice for Order: {order._id}</Text>
{order.products.map((p, i) => (
<Text key={i}>
{p.name} — Qty: {p.quantity} — ${p.amount_total}
</Text>
))}
</View>
</Page>
</Document>
);
export default Invoice;
Here, we define a simple invoice that lists the order ID and products with quantities and amounts.
Step 3: Generate PDF in Backend and Send it as Response
In your backend code, you will:
- Fetch the order data (from your database).
- Render the React PDF component to a PDF stream.
- Pipe the PDF stream to the HTTP response so the client receives the PDF file.
Example Express route:
import express from "express";
import ReactPDF from "@react-pdf/renderer";
import Invoice from "./Invoice.js"; // The React component you just created
import { getOrderById } from "./models/orderModel.js"; // Your DB function
const app = express();
app.get("/invoice/:id", async (req, res) => {
try {
const id = req.params.id;
const order = await getOrderById(id);
if (!order) {
return res.status(404).send("Order not found");
}
// Set headers for PDF response
res.setHeader("Content-Type", "application/pdf");
res.setHeader("Content-Disposition", `inline; filename=invoice_${id}.pdf`);
// Render PDF and pipe to response
const stream = ReactPDF.renderToStream(<Invoice order={order} />);
stream.pipe(res);
} catch (error) {
console.error(error);
res.status(500).send("Internal Server Error");
}
});
app.listen(3000, () => console.log("Server started on port 3000"));
What Does stream.pipe(res)
Do?
- The
ReactPDF.renderToStream()
method generates a stream of PDF data. - Calling
stream.pipe(res)
sends that PDF data directly to the HTTP response. - This way, the client’s browser receives the PDF immediately and can display or download it.
Summary
-
@react-pdf/renderer
lets you write PDFs using React components. - You need
react
andreact-dom
installed because@react-pdf/renderer
depends on React’s internals, even in backend. - Use Express (or any Node.js server) to create an API endpoint that fetches order data, generates a PDF, and streams it back.
- The user can access a URL like
/invoice/:id
to get their invoice as a PDF in the browser.
Some of the things we can do as well:
- We can customize the
Invoice
component to add logos, styles, totals, and more. - Test with Postman or your browser by visiting
http://localhost:3000/invoice/12345
(replace12345
with a valid order ID). - Look at
@react-pdf/renderer
docs for more components and styling options.
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.