Every time I wanted to add some editable content to a small site, the "modern" answer was a headless CMS. And every headless CMS wanted something before it would let me type a single word: an account, a database, an API key, a plan tier.
For a personal site or a tiny project, that always felt absurd. I'm renting a company to hold three blog posts — and if I ever want to leave, getting my own words back is an export job.
So I built JustJSON. It wants none of that.
One command, no setup
npx @kdrgny/justjson
That opens an editor in your browser. You design a schema by clicking, write your content, and everything is saved to content/*.json in your own folder. No account. No database. No API key. Nothing is uploaded anywhere — it runs on your machine and stops when you close it.
Your content is actually just files
There's no magic store behind it. A collection is a folder, an entry is a file:
content/
_schema.json ← your schema (built in the UI)
posts/
hello-world.json ← one entry per file
settings.json ← a singleton
It diffs cleanly in git, versions like code, and you can read it however you want. JustJSON only edits the files — it never holds them hostage.
Typed, and wired into your build
Content you can't use is just a pile of JSON. So JustJSON generates a typed loader from your schema:
npx @kdrgny/justjson types
import { loadPosts, loadSettings } from './content'
const posts = await loadPosts() // fully typed, slug merged in
const settings = await loadSettings() // Settings | null
Zero dependencies, reads straight from disk — so it works in any Node-based build, including Next.js server code. And for Astro, there's a dedicated loader that turns your content into real content collections in one line:
// src/content.config.ts
import { justjsonCollections } from '@kdrgny/justjson-astro'
export const collections = await justjsonCollections()
getCollection() / getEntry() just work, drafts are skipped, and saving in the editor updates the dev server without a restart.
Catch bad content before it ships
Because it's local, there's no server validating your data — so there's a command for CI:
npx @kdrgny/justjson validate --strict
It walks your content and fails the build on broken relations, duplicate slugs, missing media, and type errors. A typo never makes it to production.
From nothing to a live site
If the folder has no site yet, JustJSON can scaffold a small Astro site wired to your content, let you style it with a live preview, and hand the repo to Vercel or Netlify — all from the editor. Still no account with anyone; the files stay yours.
Try it right now — no install
If npx is too much commitment, the whole thing boots in your browser:
👉 Open the playground on StackBlitz
What it's not (being honest)
JustJSON is deliberately local-first and single-user — git is the collaboration layer, not a multiplayer server. It's MIT, and it's an early solo side project. So if you try it, I'd genuinely love to hear where it breaks or what's missing.
If you're wondering how it stacks up against Keystatic, Decap or Tina, I wrote an honest comparison here: justjson.vercel.app/vs.
Links
- ⭐ Repo: https://github.com/kdrgny-dev/justjson
- 📖 Docs: https://justjson.vercel.app/docs
- 🧪 Try in browser: https://stackblitz.com/github/kdrgny-dev/justjson/tree/main/examples/playground
If the idea of "own your content — it's just JSON" resonates, a star or a bit of feedback would make my week. 🙏

Top comments (2)
I was particularly impressed by how JustJSON generates a typed loader from the schema, allowing for seamless integration with builds like Next.js and Astro. The fact that it reads straight from disk with zero dependencies is a huge plus, making it a great option for small to medium-sized projects where simplicity is key. I'm curious, have you considered adding any features for handling media uploads or would that add too much complexity to the local-first approach?
@topstar_ai Thank you for your kind words🙏
It also stores all images locally. Maybe a feature like a free CDN could be added for every user—something like the Cloudinary plugin, for example.