Skip to content
GitHub

Key ideas

Before you open a YAML file, here are the five things that make bino click.

A bino project is a directory of YAML files. Each YAML document is a manifest — a declarative description of one building block. Every manifest has the same envelope:

apiVersion: bino.bi/v1alpha1
kind: DataSource          # the role of this document
metadata:
  name: monthly_sales     # unique identifier
spec:
  # ... kind-specific fields

The kind field tells bino what the manifest does. There are only a handful of kinds to learn:

KindRole
DataSourceLoads raw data (CSV, Excel, Parquet, Postgres, MySQL)
DataSetRuns a SQL query on top of data sources
LayoutPageDefines a page with charts, tables, and text
LayoutCardA reusable card that can be placed inside pages
ReportArtefactAssembles pages into a PDF with metadata
ComponentStyleDefines reusable visual styles
AssetRegisters images, fonts, and files

Data moves in one direction:

DataSource  →  DataSet  →  LayoutPage  →  ReportArtefact  →  PDF
   (raw)        (SQL)       (visual)        (assembly)      (output)

A DataSource registers raw data — a CSV file, an Excel sheet, a Postgres query. It becomes a named view in the query engine.

A DataSet runs SQL against those views. You can join, filter, aggregate, and window — anything DuckDB supports. The result is another named table available to layouts.

A LayoutPage arranges visual components (charts, tables, text) on a page and binds them to datasets.

A ReportArtefact collects pages into a single PDF, sets the filename and metadata, and optionally applies a digital signature.

All data transformations happen in SQL. bino embeds DuckDB, so you get full analytical SQL without needing a running database:

kind: DataSet
metadata:
  name: revenue_by_region
spec:
  query: |
    SELECT region, SUM(amount) AS total
    FROM sales_csv
    GROUP BY region
    ORDER BY total DESC

If your data is in a CSV, you query it with SQL. If it’s in Postgres, you query it with SQL. The abstraction layer is always the same.

Pages are built from a small set of visual components: ChartStructure, ChartTime, Table, Text. You place them into a page layout grid (2x2, split-vertical, 1-over-2, and more):

kind: LayoutPage
metadata:
  name: sales_dashboard
spec:
  pageLayout: 2x2
  children:
    - kind: ChartTime
      spec:
        dataset: monthly_revenue
    - kind: ChartStructure
      spec:
        dataset: revenue_by_region
    - kind: Table
      spec:
        dataset: top_customers
    - kind: Text
      spec:
        value: "Data as of ${REPORT_DATE}"

Cards group components into reusable units. Pages group into artefacts. The pieces snap together.

There is no database, no UI state, no hidden configuration. Your entire report definition lives in files on disk:

  • YAML manifests define the report structure.
  • SQL lives inside DataSet manifests (or in .sql files if you prefer).
  • Data files (CSV, Excel, Parquet) sit next to your manifests.
  • A bino.toml file at the project root holds project-level settings.

This means you get Git, code review, branching, and CI for free. Two people can work on different pages of the same report and merge without conflict.


Ready to build? Follow the Your first report tutorial. For a deeper dive into why this approach works, see Reporting as Code.