Private betav0.1.0
Docs
Format developer documentation

Next.js

Use the Format Next.js plugin to compile and render your documents inside a Next.js app.

The Format Next.js plugin compiles your documents at build time, registers module aliases for Webpack and Turbopack, and handles caching, type generation, and deployment configuration automatically.

To give you some upfront context, this is how a Format project would typically sit within a Next.js application:

app
api
pdf
route.ts
page.tsx
format
documents
invoice
assets
logo.png
data
default.json
schema.ts
index.tsx
format.config.json
format-env.d.ts
next.config.ts
package.json
.env

Installation

To add Format to an existing codebase or repo, you can use npx format init to automate the setup. This will add your Format config, the npm scripts, the gitignore entries, and the packages. Each step will confirm before editing anything.

# Install the Format CLI if you haven't already
npm install "@format.dev/cli" --save-dev

# Inside your repo directory, run the Format project init script
npx format init --root-dir ./format
# Install the Format CLI if you haven't already
pnpm add "@format.dev/cli" --save-dev

# Inside your repo directory, run the Format project init script
pnpm dlx format init --root-dir ./format
# Install the Format CLI if you haven't already
yarn add "@format.dev/cli" --dev

# Inside your repo directory, run the Format project init script
yarn dlx format init --root-dir ./format
# Install the Format CLI if you haven't already
bun add "@format.dev/cli" --dev

# Inside your repo directory, run the Format project init script
bun x format init --root-dir ./format

Running the init script will bootstrap your project and make it Format-ready. We use the --root-dir option to separate your Format documents and code from your existing app, but this is fully configurable if you would like to use a different folder structure.

If you'd prefer to add all the initial required files manually, you can follow the manual installation steps.

Add the compile package

Our Next.js plugin ships with the @format.dev/compile package. Add it using the Format CLI:

npx format add "@format.dev/compile"
pnpm dlx format add "@format.dev/compile"
yarn dlx format add "@format.dev/compile"
bun x format add "@format.dev/compile"

Update your Next.js config

Wrap your Next.js config with withFormat.

next.config.ts
import type { NextConfig } from 'next'
import withFormat from '@format.dev/compile/next'

const nextConfig: NextConfig = {}

export default withFormat()(nextConfig)

The withFormat plugin will:

  • Compile your Format documents when your Next.js project starts up
  • Cache Format builds, for efficient performance
  • Make your Format document renderers available via the import statement:
    import { myPdf } from '@format:documents'. Check the example usage to learn more.
  • Automatically rebuild on changes in development, so you can develop Format document templates and styles without restarting any servers
  • Configures Next.js for deployments that include Format PDFs and their assets

Developer workflow

Learn how building PDFs fits into your development workflow.

Launch Format Studio

Open Format Studio using the npm script added earlier.

# Either:
npm run dev

# Or this, if npm run dev was taken:
npm run format:dev
# Either:
pnpm run dev

# Or this, if pnpm run dev was taken:
pnpm run format:dev
# Either:
yarn dev

# Or this, if yarn dev was taken:
yarn format:dev
# Either:
bun run dev

# Or this, if bun run dev was taken:
bun run format:dev

You will be prompted to sign in to Format or create an account. Format Studio will then be launched on: http://localhost:1234. You can now start designing and building your PDF templates in format/documents, testing out dynamic data, styles and layouts.

Launch Next.js

In a new terminal, run the Next.js dev server

npm run dev
pnpm run dev
yarn dev
bun run dev

Follow the guide below to add a Next.js route that generates PDFs from your documents. Hit that route and instantly get a PDF with your latest changes.

You can continue to iterate in Format Studio and your Next.js route will always pull in the latest template changes.

Example usage (API route)

Below is a simple example of how to use Format in Next.js.

This example creates a server-side app route that generates the invoice PDF and returns an "inline PDF" to the browser. The browser will display the PDF in the built-in PDF viewer.

app/api/pdf/route.ts
import { invoice } from '@format:documents'
import { FormatClient } from '@format.dev/client'

export async function GET() {
	const doc = await invoice.render({ customerName: 'Ada Lovelace' })

	const format = new FormatClient()
	const response = await format.pdf(doc)

	return new Response(response.body, {
		headers: {
			'Content-Type': 'application/pdf',
			'Content-Disposition': 'inline; filename="invoice.pdf"'
		}
	})
}

See the Renderer API reference for the full method documentation.

Useful

Although this is a common way to generate a PDF, it's not the only use-case in Next.js. You can also generate PDFs in client code or in edge functions.

Multi-target builds

By default, withFormat compiles a single node target. To generate PDFs in the browser or at the edge, add one or more explicit targets.

For instance, the following config would allow you to generate PDFs in API routes on the server and in the browser.

next.config.ts
import type { NextConfig } from 'next'
import withFormat from '@format.dev/compile/next'

const nextConfig: NextConfig = {}

export default withFormat({
	targets: [
		{ target: 'node' },
		{ target: 'browser', assets: 'dynamic' }
	]
})(nextConfig)

@format:documents always resolves to the first target in the array. Every target also gets a suffixed import path:

TargetSuffixed importAssetsDependencies
node@format:documents/nodeFilesystem (auto)Externalized
browser@format:documents/browserCDN via setAssetsUrlAll bundled
worker@format:documents/edgeCDN via setAssetsUrlAll bundled

With a single target, @format:documents and the suffixed path both work. With multiple targets, use the suffixed paths to import a specific target.

Per-target options override shared defaults:

next.config.ts
export default withFormat({
	inlineRemoteCss: true,
	targets: [
		{ target: 'node', bundle: ['date-fns'] },
		{ target: 'browser', assets: 'dynamic', inlineRemoteCss: false }
	]
})(nextConfig)

All targets compile in parallel. Results are cached, so subsequent dev server starts skip compilation if nothing changed.

Browser target

Import from @format:documents/browser in client components:

app/generate-pdf.tsx
'use client'

import { invoice } from '@format:documents/browser'
import { FormatClient } from '@format.dev/client'

invoice.setAssetsUrl('https://cdn.example.com/invoice/assets.zip')

const doc = await invoice.render({ customerName: 'Ada Lovelace' })

const format = new FormatClient()
const response = await format.pdf(doc)
const blob = await response.blob()

Browser targets can't read a local assets.zip. Either host the ZIP and point at it with setAssetsUrl (works in either asset mode), or use assets: 'dynamic' to build the ZIP at render time.

Edge target

Import from @format:documents/edge in edge route handlers:

app/api/pdf/route.ts
export const runtime = 'edge'

import { invoice } from '@format:documents/edge'
import { FormatClient } from '@format.dev/client'

export async function GET() {
	invoice.setAssetsUrl(process.env.ASSETS_URL!)

	const doc = await invoice.render({ customerName: 'Ada Lovelace' })

	const format = new FormatClient()
	const response = await format.pdf(doc)

	return new Response(response.body, {
		headers: { 'Content-Type': 'application/pdf' }
	})
}

Edge bundles are fully self-contained with all dependencies bundled in.

Deployment

withFormat automatically configures Next.js for production. It adds your compiled output to serverExternalPackages and outputFileTracingIncludes, so the _generated directory is included in standalone builds.

No manual configuration needed. Run next build and deploy.

Read the deployment guide for more on assets, Docker, and CI/CD.

Options

FormatNextPluginOptions

NameDescription
Compile to multiple targets with per-target options.
Default asset mode for all targets. Overridden by target-level assets.
Inline remote CSS for all targets. Overridden by target-level inlineRemoteCss.
Whether to validate against schema for all targets. Overridden by target-level validateSchema.
Name for the compiled bundle and virtual module prefix. Sets the import alias to @format:<bundleName>.
Clear the output directory before recompiling.
Override the output directory.
Explicit path to format.config.*.

targets

Description
Compile to multiple targets with per-target options.
Type
FormatTargetOptions[]
Default value
[{ target: 'node' }]

assets

Description
Default asset mode for all targets. Overridden by target-level assets. See --assets for more information on the available modes.
Type
"static" | "dynamic" | "none"
Default value
"static"

inlineRemoteCss

Description
Whether to inline remote CSS for all targets. Overridden by target-level inlineRemoteCss. See --inline-remote-css for more information.
Type
boolean
Default value
false

validateSchema

Description
Whether to validate against schema for all targets. Overridden by target-level validateSchema.
Type
boolean
Default value
true

bundleName

Description
Name for the compiled bundle and virtual module prefix. Sets the import alias to @format:<bundleName>.
Type
string
Default value
"documents"

clean

Description
Clear the output directory before recompiling.
Type
boolean
Default value
true

outDir

Description
Override the output directory.
Type
string
Default value
<rootDir>/_generated

configPath

Description
Explicit path to format.config.*.
Type
string

FormatTargetOptions

NameDescription
targetRequired
The output target.
assets
Asset mode for this target. See --assets for more information on the available modes.
inlineRemoteCss
Whether to inline remote CSS for this target. See --inline-remote-css for more information.
validateSchema
Whether to validate against schema for this target.
bundle
Packages to force-bundle (node target). The node target externalizes all deps by default. Use this for packages that won't be in node_modules at runtime. See --bundle for more information.
external
Packages to externalize (browser/worker targets). These targets bundle all deps by default. Use this for packages your runtime already provides. See --external for more information.
Was this page helpful?