Guides

How to Build a Dashboard with Observable Framework

Arkzero ResearchApr 25, 20267 min read

Last updated Apr 25, 2026

Observable Framework is a free, open-source static site generator for building data dashboards. You process data in Python, SQL, or R at build time, and the framework compiles the results into a fast static site with no server required. This guide covers creating a project, writing a Python data loader to connect a live data source, building charts with Observable Plot, and deploying to GitHub Pages with automatic daily refreshes.
A professional analyst reviewing data reports on a modern desk

Observable Framework is a free, open-source static site generator for building data dashboards. You process your data in Python, SQL, or R at build time, and the framework compiles the results into a fast static site that loads instantly with no server required. This guide walks through creating a project, writing a data loader, building charts with Observable Plot, and deploying to GitHub Pages with automatic daily refreshes.

What Observable Framework Is

Observable Framework is a static site generator built specifically for data work. The team behind D3.js and the Observable notebook platform released it as an open-source project in 2023, and it has gained steady adoption since then among data engineers and analysts who want shareable dashboards without a BI subscription.

The core idea: your data processing stays in whatever language you already know (Python, SQL, R, or Node.js), and Observable handles the front end. You write a data loader script, Framework runs it at build time, and the result is a static site that anyone can open in a browser.

This differs from traditional BI tools in one important way: there is no server running queries when a user loads the dashboard. Everything is precomputed. A dashboard built with Observable Framework loads as fast as a regular website, with no Tableau Server license, no Metabase instance to maintain, and no backend costs.

The tradeoff is data freshness. Dashboards reflect the state of your data at the last build time. For daily or weekly reporting, the static-first model is highly practical. For sub-minute data, a different architecture is needed.

Prerequisites

You need Node.js version 18 or later installed on your machine. Check your current version:

node --version

If Node.js is not installed, download it from nodejs.org or use a version manager like nvm.

If you plan to write data loaders in Python, you also need Python 3.9 or later, plus any database drivers your analysis requires (for example, psycopg2 for PostgreSQL or snowflake-connector-python for Snowflake).

Step 1: Create a New Project

Observable Framework includes a project scaffolding tool. Run this in your terminal:

npm create @observablehq

The tool asks three questions: your project name, whether you want TypeScript support, and which starter template to use. For a first project, choose the default template and skip TypeScript.

When scaffolding completes:

cd your-project-name
npm install
npm run dev

Your browser opens at http://localhost:3000 with a live preview. The development server reloads automatically as you save files.

Step 2: Understand the File Structure

Two directories matter for authoring.

src/ holds your Markdown pages, JavaScript modules, and data loaders. Each .md file in src/ becomes a page. The file at src/index.md is your home page.

dist/ holds the compiled static site, generated by npm run build. This is what you deploy.

Open src/index.md in a text editor. You will see Markdown mixed with code blocks labeled js. Those blocks execute as JavaScript in the browser. That combination is the core authoring model: write prose, embed charts.

Step 3: Write a Data Loader

Data loaders are scripts that run at build time and output data your pages reference. They can be written in Python, SQL, R, or JavaScript. Observable Framework detects the file extension and runs the script with the correct interpreter.

Create a file at src/data/sales.csv.py:

import csv
import sys

rows = [
    {"month": "2026-01", "revenue": 42000, "segment": "enterprise"},
    {"month": "2026-02", "revenue": 51000, "segment": "enterprise"},
    {"month": "2026-03", "revenue": 48000, "segment": "smb"},
    {"month": "2026-04", "revenue": 63000, "segment": "enterprise"},
]

writer = csv.DictWriter(sys.stdout, fieldnames=["month", "revenue", "segment"])
writer.writeheader()
writer.writerows(rows)

The filename convention sales.csv.py tells Framework: run this Python script and treat the stdout as a CSV. When your page references data/sales.csv, it receives the precomputed result.

For a production deployment, replace the hardcoded rows with a real database query:

import psycopg2, csv, sys, os

conn = psycopg2.connect(os.environ["DATABASE_URL"])
cur = conn.cursor()
cur.execute(
    "SELECT date_trunc('month', created_at)::date, SUM(amount), tier "
    "FROM orders GROUP BY 1, 3 ORDER BY 1"
)

writer = csv.writer(sys.stdout)
writer.writerow(["month", "revenue", "segment"])
for row in cur.fetchall():
    writer.writerow(row)

Your database credentials are read from environment variables, run at build time on your machine or CI server, and never included in the deployed static files.

Step 4: Build a Chart with Observable Plot

Observable Plot is the charting library included by default in every Framework project. It covers the most common chart types with a concise, composable API.

In src/index.md, add:

const sales = await FileAttachment("data/sales.csv").csv({typed: true});

Plot.plot({
  marks: [
    Plot.barY(sales, {x: "month", y: "revenue", fill: "segment"}),
    Plot.ruleY([0])
  ],
  color: {legend: true}
})

FileAttachment loads the CSV your loader produced. Plot.barY draws a grouped bar chart with color encoding for segment. Plot.ruleY([0]) adds a zero baseline so bars do not mislead. The color: {legend: true} option renders a legend automatically.

Save the file. The development server updates the preview in under a second.

Step 5: Add a Grid Layout

Observable Framework ships with built-in CSS grid classes for arranging dashboard panels. Update your src/index.md:

<div class="grid grid-cols-2">
  <div class="card">
    <h2>Monthly Revenue</h2>
    ${Plot.plot({
      marks: [Plot.barY(sales, {x: "month", y: "revenue", fill: "segment"})]
    })}
  </div>
  <div class="card">
    <h2>Total Revenue</h2>
    <span class="big-number">${d3.format("$,")(d3.sum(sales, d => d.revenue))}</span>
  </div>
</div>

grid-cols-2 creates a two-column layout that collapses to a single column on narrow screens. The card class applies a bordered, padded panel. Observable Framework's default styles produce a clean, professional dashboard without any custom CSS.

Step 6: Deploy with Automatic Data Refresh

Run the build to generate the static site:

npm run build

This outputs everything to the dist/ directory. Deploy that folder to GitHub Pages, Netlify, Vercel, or any static hosting provider.

For dashboards that need to stay current, add a GitHub Actions workflow that rebuilds on a cron schedule. Create .github/workflows/deploy.yml:

name: Build and Deploy
on:
  push:
    branches: [main]
  schedule:
    - cron: "0 6 * * *"
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install psycopg2-binary
      - run: npm install
      - run: npm run build
        env:
          DATABASE_URL: ${{ secrets.DATABASE_URL }}
      - uses: peaceiris/actions-gh-pages@v4
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: dist

The schedule cron triggers a nightly rebuild at 6 AM UTC. Your data loaders re-execute against your live database, and GitHub Pages serves the updated files. A daily reporting dashboard with no server costs and no ongoing maintenance.

When Observable Framework Is the Right Choice

Observable Framework fits well when your team needs dashboards that non-technical stakeholders can open in a browser without a BI tool account, when your data processing is already written in Python or SQL, and when you want version-controlled dashboards that live in your git repository alongside the rest of your codebase.

It is a poor fit for dashboards that require sub-hourly data freshness, or for teams with no command-line experience, since the data loader pattern and CI workflow require some comfort with a terminal.

According to Observable's published benchmarks, dashboards built with Framework typically score above 95 in Google Lighthouse performance, because the static-first model removes the round trips that slow down server-rendered analytics tools.

For teams that want to skip setup entirely and go directly from a file upload to a shareable analysis, VSLZ handles data ingestion and visualization from a single upload with no configuration needed.

Summary

Observable Framework gives analysts a practical path from raw data to a deployed, shareable dashboard: write data processing in Python or SQL, build charts with Observable Plot, deploy as a static site, and automate daily rebuilds with GitHub Actions. The full workflow, from project creation to a live dashboard that refreshes every morning, takes under an hour to set up for the first time.

FAQ

What is Observable Framework used for?

Observable Framework is used for building and deploying static data dashboards and reports. It lets you write data processing code in Python, SQL, R, or JavaScript and combines it with front-end visualizations built in Observable Plot or D3. The output is a fast static website that can be hosted on GitHub Pages, Vercel, or Netlify.

Is Observable Framework free to use?

Yes. Observable Framework is open source and released under the ISC license. You can use it for commercial projects at no cost. Observable also offers a paid hosted platform (observablehq.com) with collaboration features, but the framework itself can be self-hosted for free.

What languages can I use in Observable Framework data loaders?

Observable Framework data loaders support any language installed on your machine or CI server. Commonly used languages include Python, R, SQL (via DuckDB or other CLI tools), JavaScript (Node.js), and TypeScript. The loader is identified by file extension: a file named sales.csv.py runs as Python, sales.csv.sql runs as SQL, and so on.

How do I update data in an Observable Framework dashboard?

Data updates by rebuilding the site. You run npm run build locally, or automate it with a scheduled GitHub Actions workflow. A common pattern is to trigger a rebuild every morning using a cron schedule (0 6 * * *), which runs your data loaders, fetches fresh data, and redeploys the static site. This gives you a daily-refreshed dashboard with no server infrastructure.

Do I need to know JavaScript to use Observable Framework?

Basic JavaScript knowledge helps, but you do not need to be a JavaScript developer. Observable Plot, the charting library bundled with Framework, is concise and well-documented with many copy-paste examples. Data processing can be done entirely in Python or SQL using data loaders, so the JavaScript you write is limited to loading data and calling Plot functions to render charts.

Related

OpenMetadata data catalog interface showing database schema discovery
Guides

How to Set Up OpenMetadata for Data Discovery

OpenMetadata is an open-source data catalog that gives teams a single place to discover, document, and govern their data assets. Setting it up takes under 30 minutes using Docker: spin up the containers, log into the UI at localhost:8585, then connect your first data source using one of 90+ pre-built connectors. Once ingestion runs, every table, column, and owner is searchable and lineage-linked across your entire stack.

Arkzero Research · Apr 29, 2026
Streamlit logo on a clean white background
Guides

How to Build a Data Dashboard with Streamlit

Streamlit is an open-source Python library that turns a script into a shareable web dashboard without any front-end code. Install it with pip, write a Python file that loads your CSV with pandas, add sidebar widgets for filtering, and render interactive charts with Plotly. Push the file to GitHub, connect it to Streamlit Community Cloud, and anyone with the URL can view live results. No server configuration required.

Arkzero Research · Apr 29, 2026
Airbyte Cloud data integration platform
Guides

How to Set Up Airbyte Cloud for Data Syncing

Airbyte Cloud is a managed data integration platform that syncs data from SaaS tools, databases, and APIs into a central warehouse without requiring Docker, infrastructure, or engineering resources. A free 30-day trial lets you connect sources like Salesforce, HubSpot, Stripe, or Google Sheets to destinations like BigQuery, Snowflake, or Postgres in minutes. This guide walks through the full setup from account creation to your first automated sync.

Arkzero Research · Apr 29, 2026