PortalJS: an AI-native framework for building data portals from a brief
🌀 AI-native framework for building data portals. Scaffold a full portal from a brief and load datasets in minutes with agentic skills — any backend (CKAN, GitHub, Frictionless).
At a glance
- What is it?
- PortalJS scaffolds a Home, Catalog and dataset page as plain Next.js code, with optional Claude Code skills that pick the stack and load the data. The architecture is opinionated, the AI layer is optional, and CKAN stays a first-class backend.
- Who is it for?
- Adopt PortalJS if you need a public-facing open data portal and you are willing to run Next.js, with or without the Claude Code skills. Do not adopt it if you need a governed warehouse with table-level access control, or if you cannot run Node 22 or newer.
- Can I use it commercially?
- Yes. MIT 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 24 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 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem PortalJS targets: a portal is a stack decision, not a website
Most teams that publish open data start by building a frontend, then discover the hard part was never the frontend. The README puts it plainly: you have to decide where the data lives, how it is versioned, how people search it, how it is served, and how it is governed. Teams either over-build on a data warehouse they do not need, or under-build on a pile of scripts that does not scale.
PortalJS is aimed at the second group, and at the first group's escapees. It is a framework for data teams who need a catalog and a dataset page, who have files rather than tables, and who do not want to operate a warehouse to publish a CSV. The three surfaces it generates (a Home page, a Catalog at /search, and a dataset page at /@<namespace>/<slug>) are the shape almost every open data portal converges on, so the project treats them as fixed rather than configurable.
The audience is narrower than the marketing suggests. This is for teams publishing datasets to the public or across an organisation, not for internal BI dashboards. If your users want to run SQL against governed tables with row-level permissions, a portal is the wrong artefact and PortalJS is the wrong tool.
One DataProvider seam and a storage spectrum from flat files to DuckLake
The architecture diagram in the README describes four layers. At the top, the skills decide and build. Below them, the three surfaces read data through a single DataProvider contract. Below that, providers are pluggable: static or git files, CKAN, OpenMetadata, and git-LFS with Cloudflare R2. At the bottom sits storage and compute, presented as a spectrum rather than a fixed choice: flat files, then Git-LFS plus R2, then Parquet on R2 queried with DuckDB, then a warehouse or CKAN.
The interesting design decision is the seam. Because the surfaces only ever talk to a DataProvider, swapping a static JSON catalogue for a CKAN instance should not require editing a page component. That is the claim worth testing, and it is the kind of claim that either holds or falls apart the first time a backend returns metadata in a shape the dataset page does not expect.
The default recommended path is git plus object storage plus Parquet, queried with DuckDB, which the README calls an open lakehouse instead of a classic warehouse. DuckLake is offered for living, incremental tables. Cloudflare R2 is the default substrate, with Workers for runtime, D1 for the catalog and Pages for static hosting, but the README is explicit that object storage stays S3-compatible and R2 is a default, not a lock-in. Whether that holds in practice depends on how much of the generated code reaches for R2-specific APIs, which the README does not enumerate.
Installing PortalJS and getting a portal running on localhost:3000
The quickstart requires Node 22 or newer and nothing else. The create command scaffolds a portal directory, and npm run dev serves it on port 3000.
npm create portaljs@latest my-portal
cd my-portal
npm run dev # → http://localhost:3000What you should see is a working portal over sample data with three routes: the Home page, a Catalog at /search, and a dataset page at /@<namespace>/<slug>. The generated code is plain, editable Next.js. To add your own data, the README says to put a CSV or JSON file in datasets.json and it renders automatically.
If you want the skills that do the assembly, they install once into your personal Claude Code scope so they are available from any directory. The installer is a shell script fetched from the repository.
curl -fsSL https://raw.githubusercontent.com/datopian/portaljs/main/scripts/install-portaljs-skills.sh | bashAfter restarting Claude Code or opening a new session, typing a slash lists the skills. The README names /portaljs-architect for stack advice, /portaljs-new-portal for scaffolding from a brief, /portaljs-add-dataset for loading data, /portaljs-connect-ckan for pointing at a CKAN backend, and /portaljs-deploy for shipping. A session might start with /portaljs-architect if you do not know what stack you need, then move to /portaljs-new-portal with a brief such as an Auckland Council open data portal.
There is also a bare template route with no AI involved. It uses tiged to pull the portaljs-catalog example, then installs and runs it.
npx tiged datopian/portaljs/examples/portaljs-catalog my-portal
cd my-portal && npm install && npm run dev # → http://localhost:3000Both routes land on the same three surfaces over sample data. The difference is who writes the scaffolding code: you, or the agent.
Where PortalJS is the wrong tool, and what the documentation leaves open
The skills are Claude Code skills. That is not a neutral implementation detail. If your team standardises on a different assistant, or on no assistant at all, the agentic half of the framework is unavailable and you are left with the bare template, which is a reasonable Next.js starter and nothing more. The README points at .claude/INSTALL.md for other install options, including a versioned plugin or running from a clone of the repository, but the skill format is still Claude Code's.
The second limitation is the substrate. The recommended path assumes Cloudflare R2, Workers, D1 and Pages. The README stresses that R2 is S3-compatible and not a lock-in, but a portal that uses Workers and D1 for its catalog is not portable to a plain Node host without rework. Teams with an existing AWS or on-premises deployment should read the architecture section as a description of the default, not a menu of equals.
Third, governance is thin. The README lists metadata as one of the decisions the skills advise on, and CKAN remains a first-class backend precisely because it brings its own governance model. If you need per-user access control on datasets, lineage, or audit trails, PortalJS gives you a frontend over a backend that has those properties, not the properties themselves.
Finally, the README does not document rollback, nor what happens when a generated portal drifts from the skill templates after you have edited it by hand. That is a real operational question for anyone who plans to regenerate rather than maintain.
PortalJS against CKAN alone: a frontend over a catalog versus a catalog with a frontend
The obvious alternative is CKAN by itself. CKAN is a full data portal server: it stores datasets, exposes a catalogue API, handles organisations and users, and ships its own theming layer. PortalJS takes the opposite position. It is a frontend framework that treats CKAN as one provider among several, alongside static files, OpenMetadata and git-LFS with R2.
The practical difference shows up on day one. With CKAN alone you install a Python application, a database and a search index, and you get a portal. With PortalJS you run npm create portaljs@latest, get a Next.js site in under a minute, and connect CKAN later with /portaljs-connect-ckan if you need it. That ordering suits teams whose data is currently files and whose governance requirements may never arrive.
It cuts the other way too. CKAN gives you a stable metadata schema, an API that other tools already integrate with, and a plugin ecosystem. PortalJS gives you a codebase you own and are expected to edit. If your organisation already runs CKAN and is happy with it, PortalJS is a replacement for the theming layer, not for the catalog, and the migration cost is real. If your organisation has no catalog at all and a folder of CSV files, PortalJS is the shorter path to something people can browse.
A second comparison is against building the portal yourself in Next.js. That is genuinely what PortalJS generates, so the value on offer is the three surfaces, the DataProvider contract and the sample data wiring, not a runtime you cannot escape.
Maintenance, releases and what the MIT licence means for a portal you ship
The repository is not archived, and the last push was on 2026-09-07. The most recent release listed is [email protected] on 2026-06-18, following 0.5.0 and 0.4.0 three days earlier. The scaffolding package is therefore still at 0.x, which in npm terms means the template's shape can change between minor versions. The root package.json keeps the workspace private and pins engines to Node 22 or newer, so an upgrade path that drops Node 22 support would be a breaking change for anyone on the current minimum.
Release management runs through Changesets, with changeset and release scripts in the root package.json, and a verify script that wraps setup, lint, typecheck, test and build. That is a conventional monorepo setup, and it means contributing a fix follows the usual pattern: add a changeset, run npm run verify, open a pull request.
The licence is MIT, stated in both the repository and package.json. In practice that means you can ship a generated portal commercially, modify it, and keep your changes closed. It also means there is no warranty and no obligation on Datopian to maintain any particular skill or provider. The MIT badge in the README is a licence identifier, not a support commitment. If your organisation requires a support contract or an indemnity, the licence does not provide one, and that is a procurement question rather than a legal one.
Editorial conclusion
Adopt PortalJS if you need a public-facing open data portal and you are willing to run Next.js, with or without the Claude Code skills. Do not adopt it if you need a governed warehouse with table-level access control, or if you cannot run Node 22 or newer. Before committing, verify one thing: that the DataProvider seam actually isolates your chosen backend, by swapping datasets.json for a CKAN source in a throwaway portal and confirming no page component changes.
Frequently asked questions
What is PortalJS used for?
It is a framework for building data portals: a Home page, a Catalog at /search and a dataset page at /@<namespace>/<slug>. It scaffolds those surfaces as plain, editable Next.js code and reads data through a single DataProvider contract, so the backend can be static files, CKAN, OpenMetadata or git-LFS with R2.
How do I use PortalJS in a React or Next.js project?
You run npm create portaljs@latest my-portal, then cd my-portal and npm run dev, which serves the portal on http://localhost:3000. The output is a Next.js application with three routes over sample data, and the README says adding your own CSV or JSON to datasets.json makes it render automatically.
How do I connect PortalJS to CKAN?
The README lists a /portaljs-connect-ckan skill that points the generated portal at a CKAN backend. CKAN is described as a first-class provider alongside static files, OpenMetadata and git-LFS with R2, and because the surfaces read only through a DataProvider, the source can change without touching a page.
Does PortalJS require an AI assistant to work?
No. The README documents a bare template route using npx tiged datopian/portaljs/examples/portaljs-catalog, followed by npm install and npm run dev. The Claude Code skills are an optional layer that scaffolds the same three surfaces over sample data.
What is the PortalJS licence?
MIT, stated in the repository and in the root package.json. That permits commercial use and modification, and carries no warranty or support obligation from the maintainers.
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/datopian-portaljs)