Getting Started
Your First Report
Create a complete invoice report with headers, detail rows, expressions, and formatting.
Overview
This walkthrough creates a realistic invoice report that demonstrates every core concept: multiple band types, text components with expressions, data binding, and built-in formatting functions.
The complete schema
const invoiceSchema = {
version: '1.0',
type: 'report',
locale: 'en-US',
page: {
size: 'A4',
orientation: 'portrait',
margins: { top: 30, right: 30, bottom: 30, left: 30 },
},
dataSource: 'invoice',
bands: [
{
type: 'header',
height: 120,
components: [
{
type: 'text',
position: { x: 0, y: 0, width: 250, height: 30 },
content: '{{company.name}}',
fontSize: 22,
fontWeight: 'bold',
color: '#1e293b',
},
{
type: 'text',
position: { x: 0, y: 35, width: 250, height: 20 },
content: '{{company.address}}',
fontSize: 11,
color: '#64748b',
},
{
type: 'text',
position: { x: 350, y: 0, width: 180, height: 30 },
content: 'INVOICE',
fontSize: 22,
fontWeight: 'bold',
textAlign: 'right',
color: '#6366f1',
},
{
type: 'text',
position: { x: 350, y: 35, width: 180, height: 20 },
content: '#{{invoiceNumber}}',
fontSize: 11,
textAlign: 'right',
color: '#64748b',
},
{
type: 'text',
position: { x: 350, y: 55, width: 180, height: 20 },
content: '{{formatDate(issueDate, "MMMM d, yyyy")}}',
fontSize: 11,
textAlign: 'right',
color: '#64748b',
},
{
type: 'text',
position: { x: 0, y: 80, width: 250, height: 20 },
content: 'Bill to: {{customer.name}}',
fontSize: 12,
fontWeight: 'bold',
},
{
type: 'text',
position: { x: 0, y: 98, width: 250, height: 20 },
content: '{{customer.address}}',
fontSize: 11,
color: '#64748b',
},
],
},
{
type: 'detail',
height: 28,
dataBinding: 'items',
components: [
{
type: 'text',
position: { x: 0, y: 4, width: 250, height: 20 },
content: '{{item.description}}',
fontSize: 12,
},
{
type: 'text',
position: { x: 260, y: 4, width: 60, height: 20 },
content: '{{item.quantity}}',
fontSize: 12,
textAlign: 'center',
},
{
type: 'text',
position: { x: 330, y: 4, width: 90, height: 20 },
content: '{{formatCurrency(item.unitPrice, "USD")}}',
fontSize: 12,
textAlign: 'right',
},
{
type: 'text',
position: { x: 430, y: 4, width: 100, height: 20 },
content: '{{formatCurrency(item.total, "USD")}}',
fontSize: 12,
fontWeight: 'bold',
textAlign: 'right',
},
],
},
{
type: 'footer',
height: 80,
components: [
{
type: 'text',
position: { x: 330, y: 10, width: 90, height: 20 },
content: 'Subtotal:',
fontSize: 12,
textAlign: 'right',
color: '#64748b',
},
{
type: 'text',
position: { x: 430, y: 10, width: 100, height: 20 },
content: '{{formatCurrency(sum(items, "total"), "USD")}}',
fontSize: 12,
textAlign: 'right',
},
{
type: 'text',
position: { x: 330, y: 35, width: 90, height: 20 },
content: 'Total:',
fontSize: 14,
fontWeight: 'bold',
textAlign: 'right',
},
{
type: 'text',
position: { x: 430, y: 35, width: 100, height: 20 },
content: '{{formatCurrency(sum(items, "total"), "USD")}}',
fontSize: 14,
fontWeight: 'bold',
textAlign: 'right',
color: '#6366f1',
},
{
type: 'text',
position: { x: 0, y: 55, width: 300, height: 20 },
content: 'Thank you for your business!',
fontSize: 11,
color: '#64748b',
},
],
},
],
}
The data
const invoiceData = {
company: {
name: 'Acme Corp',
address: '123 Main Street, San Francisco, CA 94105',
},
customer: {
name: 'Jane Smith',
address: '456 Oak Avenue, Portland, OR 97201',
},
invoiceNumber: 'INV-2026-001',
issueDate: '2026-04-12',
items: [
{ description: 'Web Design Services', quantity: 1, unitPrice: 2500, total: 2500 },
{ description: 'Frontend Development', quantity: 40, unitPrice: 150, total: 6000 },
{ description: 'API Integration', quantity: 16, unitPrice: 175, total: 2800 },
{ description: 'QA Testing', quantity: 8, unitPrice: 125, total: 1000 },
],
}
Render and output
import { renderReport, renderToHtml } from '@nextreport/engine'
const result = renderReport(invoiceSchema, invoiceData)
const html = renderToHtml(result)
// Write to file or serve via HTTP
import { writeFileSync } from 'fs'
writeFileSync('invoice.html', html)
Understanding the schema
Header band
The header band renders once at the top. It contains seven text components:
- Company info on the left (name and address)
- Invoice label and number on the right, with accent color
- Date formatted using
formatDatewith a human-readable pattern - Customer billing info below
Detail band
The detail band has dataBinding: 'items', which tells the engine to iterate over the items array. Each element becomes available as item (the engine derives the singular form automatically by removing the trailing “s”).
Each row shows the description, quantity, unit price, and line total. Currency values use formatCurrency for consistent formatting.
Footer band
The footer uses sum(items, "total") to calculate the subtotal across all line items. This built-in function takes an array and a property name, returning the sum of all values.
Next steps
- Schema Overview — full reference for schema structure
- Expressions — all built-in functions and expression syntax
- Render API — render reports via the REST API