Observable Framework: a static site generator where data loaders run at build time
A static site generator for data apps, dashboards, reports, and more. Observable Framework combines JavaScript on the front-end for interactive graphics with any language on the back-end for data analysis.
At a glance
- What is it?
- Observable Framework is an ISC-licensed TypeScript static site generator for data apps, dashboards and reports. Its distinguishing mechanism is the data loader: any language on the back end precomputes a static snapshot of the data during the build.
- Who is it for?
- Adopt Observable Framework when the data behind your dashboard changes on a schedule and the front end needs to stay static, and when your team is willing to write loaders in whatever language already touches the data. Do not adopt it if you need per-request queries against a live database or a CMS-style editing workflow; the build-time loader model is the wrong shape for both.
- Can I use it commercially?
- Yes. ISC is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 137 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 28, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem Observable Framework solves: dashboards that do not wait on a query
Most dashboard stacks put a query between the page and the data. The browser loads, the request goes out, the database answers, and the chart appears. Observable Framework moves that query to build time. Its README describes the project as a static site generator for data apps, dashboards and reports, and states that it features data loaders that precompute static snapshots of data at build time for dashboards that load instantly. The audience follows from that design: analysts and engineers who publish a data product on a refresh schedule, not a per-visitor query. A daily operations report, a published dataset explorer, a monthly metrics page. If your data changes once an hour or once a day, the build-time snapshot is the right granularity. If it changes with every user action, this is the wrong tool, and no amount of front-end work fixes that.
How the build works: markdown pages, data loaders, and a static output directory
The repository layout shows the shape of the system. There is a src/ directory holding the TypeScript implementation, a docs/ directory that is itself a Framework site (the package scripts include docs:build and docs:deploy running the same CLI), a templates/ directory shipped in the npm package, and a top-level observablehq.config.ts. The package exposes a single binary, observable, mapped to dist/bin/observable.js. Pages are authored in markdown, and JavaScript on the front end handles interactive graphics. The back end is deliberately unconstrained: the README says Framework combines JavaScript on the front end with any language on the back end for data analysis. That is what the loader mechanism buys. A loader is a program, and the examples directory lists loaders for Airtable, Arrow, Census, Databricks, DuckDB, Elasticsearch, GitHub and Google Analytics, among others. The loader runs during the build, writes a snapshot, and the deployed site serves that snapshot as a static file. The cost is honest: whatever the loader cannot compute at build time does not exist on the page.
Installing Observable Framework and building a first page
The package is published as @observablehq/framework and the executable is named observable. The README points readers to https://observablehq.com/framework/ for documentation and to the examples directory in the repository for working projects, so the install path below follows the package metadata rather than a quoted quickstart.
"bin": {
"observable": "dist/bin/observable.js"
}That entry from the repository's package.json is the CLI you invoke. The repository's own scripts show the two commands the tool is built around: preview during development and build for output. Its dev script runs preview with the flags below against the docs site.
"dev": "tsx watch --ignore docs --no-warnings=ExperimentalWarning ./src/bin/observable.ts preview --no-open --cors"When the site is ready to ship, the repository provides a build script that invokes the CLI's build command.
"docs:build": "tsx --no-warnings=ExperimentalWarning ./src/bin/observable.ts build"The project configuration lives in observablehq.config.ts at the root, the same file name used by this repository itself. What you should see after a successful build is a directory of static assets with no server-side runtime required, which is the whole point of precomputed loaders.
Where the build-time snapshot model breaks down
The limitation is structural, not a bug list. Because loaders precompute snapshots at build time, the freshness of every number on the page is bounded by how often you rebuild. A dashboard that must reflect a row inserted thirty seconds ago cannot be built this way; you would need a request-time API and a front end that calls it, which is a different architecture. The second constraint is loader cost. A loader that pulls a large extract from a warehouse runs on every build, so build times grow with data volume and with the number of loaders. The repository's test scripts give a hint about how seriously the project treats build behaviour: the mocha suite runs with a 30 second timeout and a fixed TZ of America/Los_Angeles, which suggests builds are expected to take real time and to be sensitive to environment. Third, the documentation is spread across the website rather than the README. The README is short by design and defers to the docs site, so anyone evaluating the project from the repository alone will find the operational details, including deployment guidance, outside the files listed here.
Observable Framework compared with a query-time dashboard stack
The obvious alternative is a dashboard tool that queries a live database from the browser or from a server on each request. Those tools answer a different question: they show the current state of a system, and they accept the latency and the operational surface of a running backend in exchange. Observable Framework trades that away. There is no query at page load, so there is no query latency, no connection pool, no database credential in the deployed artifact. What you give up is immediacy and, in some cases, interactivity that depends on data the loader did not anticipate. The comparison is not about which is better; it is about whether your data has a build cadence. A published report has one. An incident console does not. If your team already writes analysis in Python, R or SQL, the loader model lets that code run at build time instead of being rewritten into a browser-compatible query layer, which is the concrete difference in approach.
Maintenance, releases and the ISC licence
The repository is not archived and the last push was on 2026-05-15. Recent releases are v1.13.4 on 2026-03-02, v1.13.3 on 2025-04-16 and v1.13.2 on 2025-01-23, so the release cadence is irregular rather than monthly, and the gap between v1.13.3 and v1.13.4 is close to eleven months. Plan upgrades around that rhythm rather than assuming frequent patch releases. The package is published to npm with public access and ships dist JavaScript, CSS and the templates directory. The licence is ISC, a permissive licence that the package.json states directly; that is a fact about the project's terms, not legal advice, and anyone embedding the output in a commercial product should read the LICENSE file in the repository rather than take this paragraph as counsel. Upgrade cost is dominated by your own loaders and page code, not by the framework: the CLI surface is small, and the repository keeps its own documentation site built with the same tool, which means the docs and the implementation move together.
Editorial conclusion
Adopt Observable Framework when the data behind your dashboard changes on a schedule and the front end needs to stay static, and when your team is willing to write loaders in whatever language already touches the data. Do not adopt it if you need per-request queries against a live database or a CMS-style editing workflow; the build-time loader model is the wrong shape for both. Before committing, verify that the loader examples in the repository cover your data source, check what the docs say about deployment targets, and confirm the Node version your environment provides against the package's engines field.
Frequently asked questions
How do I install Observable Framework?
It is published on npm as @observablehq/framework and is normally installed as a development dependency, which puts the observable binary in your project. From there the repository's own scripts run preview locally and build to produce the static output.
What is a data loader in Observable Framework?
A data loader is a program that runs during the build and precomputes a static snapshot of data, so the deployed dashboard loads without querying a database. The README describes loaders as the feature that makes dashboards load instantly, and the examples directory includes loaders for sources such as DuckDB, Databricks, Airtable and Census.
Can I use a language other than JavaScript on the back end with Observable Framework?
Yes. The README states that Framework combines JavaScript on the front end for interactive graphics with any language on the back end for data analysis, which is why the loader examples cover several different data systems.
What licence does Observable Framework use?
The package.json declares the licence as ISC, and the repository contains a LICENSE file at its top level. It is a permissive licence, but the file itself is the authority if the terms matter to your use.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/observablehq-framework)
Community notes