PortalJS
The AI-native framework for building data portals.
Describe the portal you want β your agent helps you choose an architecture, scaffolds it, and loads your data.
Docs
Β·
Discussions
Β·
Report a bug
Why PortalJS
Building a data portal has always meant more than a website. You have to decide where the data lives, how it's versioned, how people search it, how it's served, and how it's governed β and then wire a frontend on top. Teams either over-build on a heavy data warehouse they don't need, or under-build on a pile of scripts that doesn't scale.
PortalJS is an open-source, agentic skills framework that helps data teams build, develop, and ship data portals β and the data infrastructure underneath them. It isn't only a frontend. The skills do two jobs:
- Advise β given what you're building, what your data is, and what it's for, they recommend an architecture: storage, compute, catalog, access, hosting, metadata.
- Build β they scaffold that stack as plain, editable Next.js code with no lock-in.
It is opinionated but open: the recommended modern path is git + object storage (Cloudflare R2) + Parquet + DuckLake + DuckDB β an open lakehouse instead of a classic warehouse β but a traditional datastore (CKAN, a warehouse) stays a first-class option when you need it. You always own plain code.
Built and maintained in the open by Datopian and the PortalJS community.
Architecture at a glance
π§ you describe what you want to build
β
βΌ
ββ π€ AGENTIC SKILLS ββββββββββββββββββββββββββββββββββ decide + build
β /architect Β· /new-portal Β· /add-dataset Β· /add-chart Β· /add-map β¦
β°β generates plain, editable Next.js code β no lock-in
β
βΌ
ββ π₯οΈ SURFACES ββββββββββββββββββββββββββββββββββββββββ what users see
β π Home / π Catalog /search π Showcase /@ns/slug
β°β read data through one DataProvider contract
β
βΌ
ββ π PROVIDERS βββββββββββββββββββββββββββββββββββββββ pluggable backends
β π staticΒ·git π CKAN π OpenMetadata ποΈ git-LFS + R2
β°β swap the source without touching a page
β
βΌ
π¦ STORAGE + COMPUTE β choose your point on the spectrum:
flat files ββΆ Git-LFS + R2 ββΆ Parquet + DuckLake + π¦ DuckDB ββΆ warehouse / CKAN
simplest β open lakehouse (default) heaviest
βοΈ Substrate β Cloudflare R2 (storage) Β· Workers (runtime) Β· D1 (catalog) Β· Pages (static)
object storage stays S3-compatible β R2 is the default, never a lock-in
Three surfaces. Every data portal is built from three: a Home page that explains
it and offers search, a Catalog (/search) to discover datasets, and a Showcase
(/@<namespace>/<slug>) to explore one dataset β metadata, preview, download/API, and
charts/maps. (Core concepts β)
One seam. The surfaces read data only through a DataProvider, so the source β static
files today, a CKAN or lakehouse backend tomorrow β can change without touching a page.
See ROADMAP.md for the full model and the
architecture decision framework
for how /architect turns your needs into a stack.
Build a portal with your AI assistant
PortalJS ships Claude Code skills that turn a brief into a working portal.
Setup
The skills live in this repo under .claude/commands/. The quickest
way to try them is from a clone:
git clone https://github.com/datopian/portaljs
cd portaljs
claude
Claude Code auto-discovers the slash commands from .claude/commands/ β no install step.
Type / in the session to see them.
Install anywhere: the skills and template are also packaged as a Claude Code plugin and can be installed into
~/.claude/commands/so you can run them from any project. See.claude/INSTALL.md.
Use
If you're not sure how to set up your portal, start with the advisor, then build:
/architect we have ~200 public CSVs, updated quarterly, and must publish DCAT-AP
/new-portal "Auckland Council open data portal"
/add-dataset ./data/air-quality.csv
/add-dataset https://example.com/parks.geojson
The skills are interactive β if your brief is thin, they interview you in short rounds
rather than erroring. /architect recommends a stack and hands off; /new-portal
scaffolds the three surfaces; /add-dataset appends to the datasets.json manifest and
the showcase renders automatically at /@<namespace>/<slug>. Run npm run dev and you
have a portal.
Prefer to build by hand? Clone the canonical template β the skills are a convenience, not a requirement:
npx degit datopian/portaljs/examples/portaljs-catalog my-portal
Available skills
| Skill | What it does |
|---|---|
/architect |
Recommend an architecture (storage/compute/catalog/access/hosting/metadata) from your needs, then hand off β the advisory entry point |
/new-portal |
Scaffold a new portal (Home + Catalog + Showcase) from a brief |
/add-dataset |
Add a CSV, TSV, JSON, or GeoJSON dataset β appends to the manifest; its showcase renders automatically |
/add-chart |
Add a chart to a dataset's showcase Views section |
/add-map |
Render GeoJSON on an interactive map in the showcase |
/connect-ckan |
Feed the catalog and showcases from a CKAN backend |
/deploy |
Deploy to Cloudflare Pages, Vercel, or static hosting |
/check-data-quality |
Audit a dataset for quality issues (schema, nulls, types) |
More skill families β metadata schemas (Frictionless/DCAT), more backends (OpenMetadata,
git-LFS+R2), a DuckDB data layer, and access control β are on the roadmap.
Write your own β see .claude/AUTHORING.md.
What's in this repo
.claude/commands/ the agentic skills (slash commands)
examples/ reference portals β portaljs-catalog is the canonical template
packages/
core/ layout/UI components (@portaljs/core)
ckan/ CKAN catalog UI + React (@portaljs/ckan)
ckan-api-client-js/ pure CKAN API client (@portaljs/ckan-api-client-js)
site/ portaljs.com β the marketing site + docs
ROADMAP.md direction, the four contracts, sequencing
The canonical template, examples/portaljs-catalog, is where
the three surfaces and the DataProvider seam live β read it before building.
What makes it different
- π± Open source, MIT, no lock-in β every skill emits plain Next.js you can fork and own.
- π§ Advisory, not just generative β
/architecthelps you decide the infrastructure, not only scaffold a UI. - π¦ Open lakehouse by default β git + R2 + Parquet + DuckLake + DuckDB over a heavy warehouse, with DuckDB as the query engine. A datastore/warehouse stays a supported choice.
- βοΈ Cloudflare-first, portable β R2 / Workers / D1 / Pages as the default substrate, but object storage stays S3-compatible.
- π§© Decoupled, any backend β one
DataProvidercontract in front of CKAN, DKAN, OpenMetadata, DataHub, GitHub, Frictionless, plain files β or your own. - π¨ Bring your own stack β adopt the template or lift the skills and the three-surface model into an app you already have.
Examples
Reference implementations live in examples/:
| Example | Backend |
|---|---|
portaljs-catalog |
Canonical template β Home + Catalog + Showcase over a static manifest |
portaljs-template |
Minimal single-page starter |
ckan Β· ckan-ssg |
CKAN |
github-backed-catalog |
GitHub |
dataset-frictionless |
Frictionless Data Package |
fivethirtyeight Β· openspending Β· turing |
Real-world portals |
Community & support
- π¬ Discord β live chat and help: join the server
- π£οΈ Discussions β questions, ideas, show-and-tell: github.com/datopian/portaljs/discussions
- π Issues β bugs and feature requests: open an issue
- π Docs β portaljs.com/opensource
Contributing
PortalJS is built in the open and we welcome contributions of all sizes β new skills, examples, docs, and fixes. See CONTRIBUTING.md to get started, and read ROADMAP.md and VISION.md for where the project is headed.