Core concepts

ERA Markup

Active Development!

These are available to try, but may change dramatically. Currently the only implementation of a ERA Markup renderer is inside of the Cotera App. We put the page up here so that people knew about it and could express interest

Fearless from source to dashboards

One of the weirdest things we find about the data analytics ecosystem is that it seems like the modeling and visualization tooling are totally disjoint. Tools like looker are completely different skill sets and have different deployment cycles to tools like dbt. It's difficult to know what dashboards may break downstream when making a change near data sources.

Typed Visualizations using your existing ERA skills

ERA contains a set of machine readable, type checked, declarative visualizations. Learning ERA makes it easy to pick up the charting language.

The following code creates a pie chart from the customers table in the database. It uses the same functions and syntax as the relation operators to fetch it's data

import { From, Count } from '@cotera/era';
import { CUSTOMERS } from './assumptions';

const CustomersByCampaignChart = From(CUSTOMERS)
  .groupBy((t) => t.pick('campaign_converted_from'))
    (t) => ({
      category: t.attr('campaign_converted_from'),
      value: Count(),
    { title: 'Customers by Campaign' }

Adding interactivity

ERA also does type checked interactivity, allowing you to have interactive dashboards that can dynamically change the queries in a much more powerful way to something like LookML.

The following describes an interactive component that has a select box that takes either Email or Review from the user. It can then rerun the macro when that input changes

import { Controls, M, Count, f, Select } from '@cotera/era';

  { source: Select({ values: ['Email', 'Review'], default: 'Email' }) },
  ({ source }) => [
    '# Review Dashboard',
    // The ERA interperter will evaluate this `f` string _runtime_ using the
    // JS interpereter to decide what to display. All of the ERA expression
    // language works the same way at runtime as in the warehouse
    f`## Showing sentiments of type ${source.upper()}`,
    // This macro runs at runtime based on the user input to decide which
    // relation to use
    M.relIf(source.eq('Email'), {
      // The type checker will make sure both branches can support the
      // downstream operations
      then: EmailSentiments,
      else: ReviewSentiments,
      .groupBy((t) => t.pick('SENTIMENT'))
      .chart.PieChart((t) => ({
        category: t.attr('SENTIMENT'),
        value: Count(),

Under the hood the ERA type checker contains "function" types called "macros" that can be used to declarative transformations of ERA code at runtime. Markup components describe type checked transformations of inputs into era charts.

At runtime, a ERA renderer can interactively collect user input and use that to create the appropriate charts. ERA macros are supported through the entire language, so you can dynamically change anything as opposed to other SQL builder approaches which only have a limited set of transforms due to SQL limitations

Ready to learn more?

Then come and say hello to us on Discord! Or head over to GitHub to try out the ERA examples on your computer.