Author Image

CEO & Co-founder of Visivo

Visivo 2.0: Insights and the Semantic Layer Are Now the Only Way to Build

Visivo 2.0 makes Insights and the semantic layer the single way to build charts. We removed legacy config and Jinja preprocessing, and this post covers what changed and why.

Visivo 2.0 release recap: Insights and the semantic layer

Today we shipped Visivo 2.0, the biggest release in the project's history. It is a deliberate, breaking simplification: there is now exactly one way to build a chart in Visivo, and it runs through Insights and the semantic layer. The legacy chart configuration is gone, and so is the Jinja preprocessing step that used to sit between your YAML and your data.

If you have been following along, none of the building blocks are new. We have been shipping them release by release since the semantic layer landed in January. What 2.0 does is commit to them. This post walks through what changed, what it unlocks, and exactly what you need to do to migrate.

One way to build a chart

Before 2.0, Visivo had two overlapping ways to define a visualization. You could wire up the older chart config directly, or you could define an Insight on top of the semantic layer. Two paths meant two mental models, two sets of docs, and two places a bug could hide.

In 2.0 there is one path. You define your data shape once in the semantic layer, then describe what you want to see as an Insight:

# project.visivo.yml
name: revenue-overview

models:
  - name: orders
    sql: "SELECT * FROM orders"
    metrics:
      - name: total_revenue
        expression: "SUM(amount)"
    dimensions:
      - name: order_month
        expression: "DATE_TRUNC('month', created_at)"

insights:
  - name: monthly-revenue
    description: "Revenue by month from the orders model"
    props:
      type: bar
      x: ?{ ${ref(orders).order_month} }
      y: ?{ ${ref(orders).total_revenue} }

The ?{ ... } query expressions reference metrics and dimensions you defined once on the model. Change the definition of total_revenue in one place, and every Insight that uses it updates. That is the whole point of a semantic layer, and in 2.0 it is the foundation everything else stands on. The full reference lives in the Insights documentation.

The semantic layer is the source of truth

A metric defined in the semantic layer is reusable, testable, and unambiguous. Instead of copy-pasting SUM(amount) into a dozen charts, where one quietly drifts the moment it adds a WHERE clause nobody else has, you define it once:

metrics:
  - name: net_revenue
    expression: "SUM(amount - refunds - discounts)"

relations:
  - name: orders_to_customers
    condition: ${ref(orders).customer_id} = ${ref(customers).id}

Metrics, dimensions, and relations compose. An Insight can pull a metric from one model and a dimension from another, and Visivo resolves the join through the relation you declared. This is the same idea that has made dbt™ the backbone of the modern data stack, applied to the visualization layer instead of stopping at the warehouse. We go deeper on the reasoning in why your metrics belong in a semantic layer.

Interactivity without a rebuild

Insights are interactive by default. Filters, splits, and sorts are expressed declaratively as interactions, and they run in the viewer without a round-trip rebuild:

insights:
  - name: revenue-by-segment
    props:
      type: bar
      x: ?{ ${ref(orders).order_month} }
      y: ?{ ${ref(orders).total_revenue} }
    interactions:
      - split: ?{ ${ref(orders).segment} }
      - sort: ?{ ${ref(orders).order_month} ASC }
      - filter: ?{ ${ref(orders).total_revenue} > 0 }

In the old model, slicing your data by a new dimension often meant defining a whole new chart. In 2.0, a split is one line, and the viewer re-aggregates live. That is the difference between a static report and something a stakeholder can actually explore.

We removed Jinja preprocessing

Earlier versions of Visivo ran your YAML through a Jinja templating pass before parsing. It was powerful, but it was also a foot-gun: a stray brace could change the meaning of your config in ways that were invisible until runtime, and it made error messages harder to trace back to the line you actually wrote.

2.0 removes the Jinja preprocessing step entirely. Dynamic behavior that used to lean on templating now has first-class homes: ${ env.VAR } for environment values, ${ ref(...) } for references between objects, and the semantic layer for anything computed. The result is a config file that means exactly what it says, which makes it far easier to review in a pull request, the way we describe in tracking dashboard changes through pull requests.

Legacy configuration is gone

This is the breaking part, so we want to be direct about it. The legacy chart syntax has been removed in 2.0. Projects that still use it will not run until they are migrated to Insights. We did not take this lightly. Carrying two systems forever would have meant a slower, more confusing product for everyone.

To soften the transition, the releases leading up to 2.0 did the groundwork:

  • v1.0.76 introduced the semantic layer (metrics, dimensions, relations), the Insights foundation, the notebook-style Explorer, and a ClickHouse source.
  • v1.0.79 made every object type editable and added Parquet-backed tables.
  • v1.0.80 brought a SQL editor into Explorer and pivotable tables.
  • v1.0.81 shipped the redesigned Explorer and removed the legacy routes.
  • v1.0.82 added metric and dimension publishing plus dashboard thumbnails, the last step before flipping the switch.

If you are on a recent 1.0.x release, you have likely already adopted most of this. The migration guide in the docs covers the mechanical changes object by object.

How to upgrade

Upgrading is the standard install path. For the open-source CLI:

pip install --upgrade visivo
# or, with the install script:
curl -fsSL https://visivo.sh | bash

Then run your project locally and let the compiler tell you what needs attention:

visivo serve

Visivo 2.0 surfaces clear, line-level errors for any legacy config it finds, pointing you at the Insight equivalent. Work through them one object at a time, commit as you go, and you have a reviewable migration in your Git history.

What this unlocks

The reason we were willing to ship a breaking release is what the single model makes possible. With one source of truth for metrics, Visivo can reason about your project as a whole, which is exactly what AI-assisted dashboard generation needs, and what makes BI-as-code genuinely scalable instead of just version-controlled. A clean semantic layer is the substrate for everything we are building next.

If you want to see Insights in action before you migrate, the examples gallery has live dashboards built entirely on the 2.0 model, and /get-started walks you from pip install to your first Insight in a few minutes.

Previously in Visivo

Visivo 2.0 is the culmination of the semantic-layer work we have been shipping all spring. For the thinking behind treating metrics as shared infrastructure rather than per-chart SQL, read why your metrics belong in a semantic layer, not in every dashboard. And to follow the releases as they ship, subscribe below. The next recap lands when the next version does.

Install command copied