Next.js Integration
Generate PDFs from Next.js applications using server actions, API routes, and the Document Stack SDK.
Installation
Bash
npm install @document-stack/sdk-nodeAdd your API key to .env.local:
.env.local
DS_API_KEY=your_api_key_hereServer Actions (App Router)
The recommended approach for Next.js App Router is server actions. The API key stays on the server — never exposed to the client.
app/actions/generate-pdf.ts
"use server";
import { DocumentStack } from "@document-stack/sdk-node";
const client = new DocumentStack({
apiKey: process.env.DS_API_KEY!,
});
export async function generateInvoice(data: {
customerName: string;
amount: number;
items: Array<{ description: string; price: number }>;
}) {
const pdf = await client.generate({
templateId: "tmpl_invoice",
data,
});
return { url: pdf.url };
}app/invoices/page.tsx
"use client";
import { generateInvoice } from "@/app/actions/generate-pdf";
import { useState } from "react";
export default function InvoicePage() {
const [pdfUrl, setPdfUrl] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
async function handleGenerate() {
setLoading(true);
const result = await generateInvoice({
customerName: "Acme Corp",
amount: 499.99,
items: [
{ description: "Consulting", price: 299.99 },
{ description: "Support", price: 200.00 },
],
});
setPdfUrl(result.url);
setLoading(false);
}
return (
<div>
<button onClick={handleGenerate} disabled={loading}>
{loading ? "Generating..." : "Generate Invoice"}
</button>
{pdfUrl && (
<a href={pdfUrl} target="_blank" rel="noopener noreferrer">
Download PDF
</a>
)}
</div>
);
}API Routes
Alternatively, use a Route Handler for REST-style endpoints:
app/api/generate/route.ts
import { DocumentStack } from "@document-stack/sdk-node";
import { NextRequest, NextResponse } from "next/server";
const client = new DocumentStack({
apiKey: process.env.DS_API_KEY!,
});
export async function POST(req: NextRequest) {
const body = await req.json();
const pdf = await client.generate({
templateId: body.templateId,
data: body.data,
});
return NextResponse.json({ url: pdf.url });
}Authentication
Always protect your API routes with authentication. The example above is simplified — add session checks or middleware before allowing PDF generation.Streaming Download
For direct PDF downloads without storing URLs:
app/api/download/route.ts
import { DocumentStack } from "@document-stack/sdk-node";
import { NextRequest } from "next/server";
const client = new DocumentStack({
apiKey: process.env.DS_API_KEY!,
});
export async function GET(req: NextRequest) {
const templateId = req.nextUrl.searchParams.get("templateId")!;
const pdf = await client.generate({
templateId,
data: { date: new Date().toISOString() },
});
const pdfResponse = await fetch(pdf.url);
const pdfBuffer = await pdfResponse.arrayBuffer();
return new Response(pdfBuffer, {
headers: {
"Content-Type": "application/pdf",
"Content-Disposition": 'attachment; filename="document.pdf"',
},
});
}Best Practices
- Keep the SDK client in a shared utility file to reuse the connection
- Use Server Actions instead of API routes for simpler code
- Add error handling with try/catch around all SDK calls
- Cache generated PDFs when the same data produces the same output
- Store
DS_API_KEYin environment variables, never in code
Next Steps
- Node.js SDK — Full SDK reference
- Node.js SDK Advanced — Streaming, batching, retries
- React Integration — Client-side patterns