Guides

Documents

Last updated on

Create and render static documents with layers

This guide walks through creating a static document with multiple layers and rendering it.

Define the Document

A document needs a name, version, and title. Unlike forms, documents don't have fields or parties—they're static content with one or more layers.

import { p } from '@paradoc/sdk'

const privacyPolicy = p.document({
  name: 'privacy-policy',
  version: '1.0.0',
  title: 'Privacy Policy',
  description: 'Our privacy policy document',
  code: 'DOC-PRIVACY-001',
})

Add Layers

Documents support multiple layers for different formats. Add inline layers for text, HTML, or Markdown content.

const privacyPolicy = p.document({
  name: 'privacy-policy',
  version: '1.0.0',
  title: 'Privacy Policy',
  defaultLayer: 'markdown',
  layers: {
    markdown: {
      kind: 'inline',
      mimeType: 'text/markdown',
      text: `
# Privacy Policy

Last Updated: January 2025

## Data Collection

We collect information you provide directly to us, including name, email, and usage data.

## Data Usage

Your data is used to provide and improve our services.
      `,
    },
    html: {
      kind: 'inline',
      mimeType: 'text/html',
      text: '<h1>Privacy Policy</h1><p>Last Updated: January 2025</p>',
    },
  },
})

Add File Layers

You can also reference external files instead of inline content. A file-backed layer's bytes come from a resolver, and the resolver is bound once, when the document is constructed — every instance derived from it afterward carries it.

import { createFsResolver } from '@paradoc/resolvers/fs'

const resolver = createFsResolver({ root: process.cwd() })

const privacyPolicy = p.document({
  name: 'privacy-policy',
  version: '1.0.0',
  title: 'Privacy Policy',
  defaultLayer: 'pdf',
  layers: {
    pdf: {
      kind: 'file',
      mimeType: 'application/pdf',
      path: '/documents/privacy-policy.pdf',
    },
    markdown: {
      kind: 'file',
      mimeType: 'text/markdown',
      path: '/documents/privacy-policy.md',
    },
  },
}, { resolver })

Render the Document

Documents return raw content directly—no renderer needed. Use the default layer or specify one explicitly.

// Render using default layer
const output = await privacyPolicy.render()
console.log(output)

// Render specific layer
const htmlOutput = await privacyPolicy.render({ layer: 'html' })
console.log(htmlOutput)

A document with file layers, built with a bound resolver as shown above, renders the same way — no resolver in the render call:

const pdfBytes = await privacyPolicy.render()

Render a file layer with no resolver bound and Paradoc throws UnboundResolverError, naming the layer and the path it wanted.

Save the Artifact

Export the document to JSON or YAML for storage or version control.

const json = privacyPolicy.toJSON()
const yaml = privacyPolicy.toYAML()
{
  "$schema": "https://schema.paradoc.dev/2026-10-02.json",
  "kind": "document",
  "name": "privacy-policy",
  "version": "1.0.0",
  "title": "Privacy Policy",
  "description": "Our privacy policy document",
  "code": "DOC-PRIVACY-001",
  "layers": {
    "markdown": {
      "kind": "inline",
      "mimeType": "text/markdown",
      "text": "..."
    }
  },
  "defaultLayer": "markdown"
}

Load it back with p.load():

const loaded = p.load(jsonString) // works with JSON or YAML

On this page