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
Create a portal — one command, nothing to install beyond Node 22+:
npm create portaljs@latest my-portal
cd my-portal
npm run dev # → http://localhost:3000
You get the three surfaces — Home, a Catalog (/search
), and a dataset Showcase
(/@<namespace>/<slug>
) — over sample data. Plain, editable Next.js, no lock-in. Add your
own CSV/JSON to datasets.json
and it renders automatically.
Build it with your AI assistant — PortalJS ships Claude Code
skills that do the assembly. Install them once (into ~/.claude/commands
):
curl -fsSL https://raw.githubusercontent.com/datopian/portaljs/main/scripts/install-portaljs-skills.sh | bash
Then, in a Claude Code session from any directory:
/portaljs-architect not sure what stack you need? start here
/portaljs-new-portal "Auckland Council open data portal"
/portaljs-add-dataset ./data/air-quality.csv
/portaljs-new-portal
scaffolds the three surfaces; /portaljs-add-dataset
(or /portaljs-add-resource
) loads data;
/portaljs-connect-ckan
points it at a CKAN backend; /portaljs-deploy
ships it. (All skills + install →)
Prefer the bare template — plain Next.js, no AI, no lock-in:
npx tiged datopian/portaljs/examples/portaljs-catalog my-portal
cd my-portal && npm install && npm run dev # → http://localhost:3000
You get Home, a Catalog (/search
), and a dataset Showcase (/@<namespace>/<slug>
) over
sample data. Add your own CSV/JSON to datasets.json
and it renders automatically.
⭐ If it's useful, a star helps others find it.
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— givenwhat you're building,what your data is, andwhat 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, queried with DuckDB — an open lakehouse instead of a classic warehouse. For living, incremental tables you can layer on DuckLake, and 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.
🧑 you describe what you want to build
│
▼
╭─ 🤖 AGENTIC SKILLS ────────────────────────────────── decide + build
│ /portaljs-architect · /portaljs-new-portal · /portaljs-add-dataset · /portaljs-add-chart · /portaljs-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 on R2 + 🦆 DuckDB ─▶ warehouse / CKAN
simplest ⭐ open lakehouse (default) heaviest
(+ DuckLake for living tables)
☁️ 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 frameworkfor how
/portaljs-architect
turns your needs into a stack.PortalJS ships Claude Code skills that turn a brief into a working portal.
Install the skills once into your personal scope so they're available from any directory:
curl -fsSL https://raw.githubusercontent.com/datopian/portaljs/main/scripts/install-portaljs-skills.sh | bash
Restart Claude Code (or open a new session) and type /
to see them. See .claude/INSTALL.md for other install options (versioned plugin, or running straight from a clone of this repo).
If you're not sure how to set up your portal, start with the advisor, then build:
/portaljs-architect we have ~200 public CSVs, updated quarterly, and must publish DCAT-AP
/portaljs-new-portal "Auckland Council open data portal"
/portaljs-add-dataset ./data/air-quality.csv
/portaljs-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. /portaljs-architect
recommends a stack and hands off; /portaljs-new-portal
scaffolds the three surfaces; /portaljs-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? The skills are a convenience, not a requirement — scaffold the template directly with the CLI:
npm create portaljs@latest my-portal
(Or grab the bare template with no prompts: npx tiged datopian/portaljs/examples/portaljs-catalog my-portal
.)
| Skill | What it does |
|---|---|
/portaljs-architect |
/portaljs-new-portal
/portaljs-add-dataset
/portaljs-add-resource
/portaljs-add-chart
/portaljs-add-map
/portaljs-add-geo
/portaljs-define-schema
/portaljs-add-dcat
/portaljs-connect-ckan
/portaljs-check-data-quality
/portaljs-migrate
/arcgis-to-portaljs
/data.json
, export every FeatureService layer via the ArcGIS REST API, convert to the serverless dual tier (PMTiles + GeoParquet), push to R2, and write a source-vs-derived parity report./portaljs-deploy
<slug>.arc.portaljs.com
URL.Large-data scaling — big files pushed to Cloudflare R2 via Git LFS — already ships in
/portaljs-add-dataset
. More skill families — metadata schemas (Frictionless/DCAT), more backends (OpenMetadata), a browser DuckDB query layer, and access control — are on the roadmap. Write your own — see .claude/AUTHORING.md.
.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.- 🌱
Open source, MIT, no lock-in— every skill emits plain Next.js you can fork and own. - 🧭
Advisory, not just generative—/portaljs-architect
helps youdecidethe infrastructure, not only scaffold a UI. - 🦆
Open lakehouse by default— git + R2 + Parquet queried with DuckDB, over a heavy warehouse; add DuckLake for living/incremental tables. 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— oneDataProvider
contract in front ofCKAN,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.
Reference implementations live in examples/:
| Example | Backend |
|---|---|
portaljs-catalog |
Canonical template— Home + Catalog + Showcase over a static manifestportaljs-template
·ckan
ckan-ssg
github-backed-catalog
dataset-frictionless
·fivethirtyeight
·openspending
turing
- 💬 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/docs
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.