Skip to main content

Data Apps

A data app is a configuration-based visualization tool that allows you to create interactive dashboards from SQL queries without writing complex frontend code.

What are Data Apps?

Data apps in Oxy are defined using YAML configuration files (.app.yml) that specify both the data processing tasks and how to visualize the results.
ℹ️ Info Data apps are designed to make it simple to transform SQL query results into meaningful visualizations with minimal effort. The .app.yml files abstract away the complexity of building dashboards, allowing you to focus on the data and insights rather than visualization code.

Data App Components

In a data app YAML file, you need to specify the following components:
ComponentDescriptionRequired
nameUnique identifier for the data appRequired
descriptionBrief explanation of the app’s purposeOptional
tasksSQL queries that prepare data for visualizationRequired
displayVisualization components to render the dataRequired

Tasks

The tasks section defines SQL queries that will extract and transform data from your databases. Each task has the following structure:
FieldDescriptionRequired
nameIdentifier for the task (referenced in display)Required
typeThe task type (currently only execute_sql is supported)Required
databaseDatabase connection to use (defined in config.yml)Required
sql_queryInline SQL query to executeRequired if sql_file not provided
sql_filePath to SQL file to executeRequired if sql_query not provided
variablesKey-value pairs for variable substitution in queriesOptional
cacheCache configuration for query resultsOptional
exportConfiguration for exporting query resultsOptional
⚠️ Warning Make sure your tasks are named uniquely as these names are referenced in the display section.

Display

The display section defines how to visualize the data produced by your tasks. Several visualization types are supported:

Markdown

Markdown blocks can be used to add formatted text, headers, and documentation:
- type: markdown
  content: |
    # Dashboard Title
    Additional formatted text here

Controls

Controls add interactive filter widgets to your app. When the user changes a control value, every task that references that control re-runs automatically and all charts and tables update. Controls are defined inline in the display list using type: control:
display:
  - type: control
    name: region
    control_type: select
    label: Region
    options:
      - All
      - North
      - South
    default: "All"

  - type: control
    name: start_date
    control_type: date
    label: From Date
    default: "2024-01-01"

  - type: control
    name: holidays_only
    control_type: toggle
    label: Holidays Only
    default: false
FieldDescriptionRequired
nameIdentifier used to reference the control value in SQL via {{ controls.<name> }}Required
control_typeWidget type: select, date, or toggleRequired
labelHuman-readable label shown above the widgetOptional
defaultInitial value when the app loadsOptional
optionsOption list for select controls — static strings or Jinja expressionsRequired for select (or use source)
sourceTask name whose first column provides options dynamically for select controlsOptional (alternative to options)
Control types
select — a dropdown menu. Populate options from a static list, from Jinja expressions, or from a task query:
# Static options
- type: control
  name: region
  control_type: select
  label: Region
  options:
    - All
    - North
    - South
  default: "All"

# Jinja-templated options — evaluated at startup so the list stays current
- type: control
  name: year
  control_type: select
  label: Year
  options:
    - "All"
    - "{{ now(fmt='%Y') }}" # current year, e.g. "2026"
    - "{{ now(fmt='%Y') | int - 1 }}" # previous year, e.g. "2025"
    - "{{ now(fmt='%Y') | int - 2 }}" # two years ago, e.g. "2024"
  default: "All"

# Dynamic options from a task
- type: control
  name: store
  control_type: select
  label: Store
  source: store_list # task name; its first column becomes the option list
  default: "All"
date — a date picker that injects a YYYY-MM-DD string. The default can be a static date or a Jinja expression:
- type: control
  name: start_date
  control_type: date
  label: From Date
  default: "{{ now(fmt='%Y-%m-%d') }}" # today's date at startup
toggle — a boolean on/off switch:
- type: control
  name: holidays_only
  control_type: toggle
  label: Holidays Only
  default: false
Using control values in SQL
Reference control values in your task SQL using Jinja syntax:
tasks:
  - name: sales
    type: execute_sql
    sql_query: |
      SELECT *
      FROM sales
      WHERE ({{ controls.region | sqlquote }} = 'All' OR region = {{ controls.region | sqlquote }})
        AND sale_date >= {{ controls.start_date | sqlquote }}
        {% if controls.holidays_only %}AND period = 'Holiday'{% endif %}
    database: local
ℹ️ Info Controls must be placed before the charts and tables they affect in the display list. The controls bar is rendered at the top of the page and stays visible as you scroll.

Bar Chart

- type: bar_chart
  title: Revenue by Category
  data: revenue_by_category # task name
  x: category # column for x-axis
  y: total_revenue # column for y-axis

Line Chart

- type: line_chart
  title: Sales Trend Over Time
  data: sales_trend
  x: month
  y: avg_sales
  x_axis_label: Month
  y_axis_label: Average Weekly Sales ($)
  series: indicator # optional: column name for multi-series lines

Pie Chart

- type: pie_chart
  title: Revenue by Region
  data: revenue_by_region
  name: region # column for slice labels
  value: total_revenue # column for slice values

Table

- type: table
  title: Filtered Sales Detail
  data: raw_sales # task name

Row (multi-column layout)

Use row to arrange multiple charts side by side:
- type: row
  columns: 2
  children:
    - type: bar_chart
      title: Revenue by Category
      data: revenue_by_category
      x: category
      y: total_revenue

    - type: pie_chart
      title: Revenue by Region
      data: revenue_by_region
      name: region
      value: total_revenue

Complete example

name: sales_dashboard
description: Interactive sales dashboard with region and date filters.

tasks:
  - name: store_options
    type: execute_sql
    sql_query: |
      SELECT 'All' AS store
      UNION ALL
      SELECT DISTINCT store FROM 'sales.csv'
      ORDER BY store
    database: local

  - name: sales_by_category
    type: execute_sql
    sql_query: |
      SELECT category, SUM(revenue) AS total_revenue
      FROM 'sales.csv'
      WHERE ({{ controls.store | sqlquote }} = 'All' OR store = {{ controls.store | sqlquote }})
        AND sale_date >= {{ controls.start_date | sqlquote }}
      GROUP BY category
    database: local

display:
  - type: control
    name: store
    control_type: select
    label: Store
    source: store_options
    default: "All"

  - type: control
    name: start_date
    control_type: date
    label: From Date
    default: "2024-01-01"

  - type: markdown
    content: |
      # Sales Dashboard
      Use the controls above to filter by store and date.

  - type: bar_chart
    title: Revenue by Category
    data: sales_by_category
    x: category
    y: total_revenue