Skip to content

← Portfolio

DashPDF

DashPDF exports Grafana dashboards and panels to PDF or PNG, with scheduled email delivery and a customer-controlled data flow.

DashPDF: export Grafana dashboards to polished PDF reports

Overview

DashPDF is a service for exporting Grafana dashboards and individual panels to PDF and PNG. It turns a working dashboard into a document that can be downloaded, archived, or regularly emailed to recipients.

DashPDF works through an app plugin installed in Grafana. The plugin runs panel queries inside the user's infrastructure, collects the dashboard JSON and prepared data frames, and sends the snapshot for rendering through an outbound request. Access to Grafana and data-source credentials remain on the user's side.

The product supports Grafana 12 and 13. Both versions are covered by the automated test matrix.

Product Features

DashPDF provides:

  • Export of a whole dashboard or a single panel
  • PDF and PNG output
  • A4 and Letter paper sizes
  • Portrait and landscape orientation
  • Paginated layout or one long page
  • Panel rows kept intact across page breaks
  • The selected time range and variable values carried into the export
  • Support for repeated panels and rows, mixed data sources, ad hoc filters, and library panels
  • Schedules with a cron expression, time zone, and relative time window
  • Email delivery of finished reports
  • A portal listing reports, connected Grafana instances, and their schedules

Recipients are configured directly on each schedule. After a run, the PDF arrives as an attachment; for a large file, the email contains a link to the report in the portal. Repeated failures pause the schedule and make the problem visible instead of silently skipping delivery.

DashPDF is currently free during its preview while the team learns how people export and deliver reports in real workflows.

Architecture

DashPDF is built as a monorepo and includes:

  • A Next.js web portal
  • A Go API with an OpenAPI contract
  • A Grafana app plugin written in TypeScript and Go
  • An internal data-source plugin that supplies saved data frames to the rendering environment
  • PostgreSQL for accounts, connected instances, tokens, snapshots, render tasks, and schedules
  • Redis for coordinating chunked snapshot uploads across API replicas
  • Mailoo as the headless CMS for the blog

Portal sign-in is separated from plugin access to the API: the browser uses its own session, while each connected Grafana instance receives a dedicated token.

For each render, the API starts an isolated Grafana instance on the same major version as the source and adds the required public panel plugins. Data sources in the copied dashboard are replaced with an internal data source that serves the frames already collected by the plugin. Headless Chrome produces the PDF or PNG.

Rendering environments are reused for the same combination of Grafana version and plugin set, then stopped after an idle period. This reduces the time needed for repeat exports while limiting the number of continuously running instances.

Infrastructure & SRE

The project has:

  • GitLab CI with code checks, tests, and quality analysis
  • Container builds with Kaniko
  • Separate images for the web portal, API, and migrator
  • GitOps deployment through Argo CD
  • A separate database-migration task before API updates
  • Health checks for the portal and API
  • Playwright end-to-end tests against Grafana 12 and Grafana 13
  • A bounded pool of rendering environments
  • Automatic deletion of snapshot payloads after their retention period
  • Limits on upload size and concurrent unfinished uploads

Snapshot frames are available only to the rendering environment inside the service boundary. The public API receives the material prepared by the plugin and manages the task, while a separate internal channel serves the temporary Grafana instance.

Engineering Challenges

The central engineering challenge in DashPDF is producing a repeatable report from a live dashboard while preserving the trust boundary around the user's Grafana.

The plugin runs queries where data-source access and user permissions are already configured. The service receives the material for one export, and rendering happens in a separate Grafana instance on a compatible version. This reproduces panels without handing the service access to the monitoring infrastructure.

Large dashboards use a chunked snapshot upload. Its state is coordinated centrally, allowing an API deployment with multiple replicas to accept different parts of the same upload.

Schedules are executed by the plugin inside Grafana. When a schedule is saved, the plugin records the query plan and later repeats it for the required time window. If the dashboard changes after the plan was recorded, the run carries a warning until the plan is recorded again.

Paginated PDF output requires its own layout pass: panels are grouped by row and moved as a unit so a chart or table is not split at a page boundary.

The result is an export and scheduled-delivery layer for an existing Grafana installation, while data-source queries and access control remain inside the user's infrastructure.