Not a service. Not a headless API. Not a dashboard you log into somewhere else. Vinum is a handful of packages you import: its admin mounts inside your route tree, its loaders run in your server, and your content lives in your own store, on your own disk. There is no instance to keep alive and no key to rotate.
// app/vinum.server.tsexport const vinum = registerVinum( defineVinum({ site: { name: "My Site" }, store: denoKvStore({ path: "./data/kv.sqlite" }), media: fsMedia({ dir: "./data/media" }), auth: { cookieName: "site_admin", secret: env("SESSION_SECRET") }, }),);Keys are strings, values are plain JSON. No ORM, no migrations framework, no proprietary encoding — anyone with a SQLite viewer can read your content. Lock-in is a bug.
Web-standard Request and Response. Web Crypto. A key-value interface with five methods. Every dependency we add is an upgrade you will one day have to perform, so we add almost none.
Nothing authored is trusted — not from an editor, not from an import file, not from an agent holding a tool. Every write passes through a pure sanitizer that drops what it does not recognise. No raw HTML from data reaches output, ever.
Vinum ships structure and a styling contract; you ship the values. An editor chooses what a block says and which variant it wears, never its colour or its spacing. That boundary is why a client can edit all afternoon without breaking the layout.
On the page it renders on, in the layout it will actually have, with your real components. Not a form on the left and a preview on the right. The inline editor and the public renderer are one code path in two modes.
This section exists because the answer elsewhere is often "you cannot". Wix's own help centre states a Wix site needs to be hosted and operated on Wix's servers; you can export a CMS collection as CSV and nothing else, so leaving means rebuilding.
Vinum exports everything as one JSON file — from the admin, or one call in code. It is not a special export mode. It is the same code path the Backup screen uses every day.
{ "version": 1, "exportedAt": 1754481600000, "entries": [ { "key": ["page", "about"], "value": { "slug": "about", "title": "About" } }, { "key": ["rev", "about", 1754000000000], "value": {} } ]}Saying who a tool is not for is how the right person recognises themselves. None of these is a roadmap item.
Vinum is small on purpose, and small has costs. The last row is the one that matters most if you are choosing between these.
| Vinum | WordPress | |
|---|---|---|
| Extending it | TypeScript in your own repo, through the same API the core blocks use. | A plugin ecosystem — and 91% of 2025's 11,334 disclosed vulnerabilities were in plugins. |
| Getting out | One JSON file with documented keys, importable into a fresh install. | Exporters exist, with fidelity that depends on which plugins wrote your content. |
| Where you edit | On the page, in its real layout, with your components. | Gutenberg. Sentiment across 340+ opinions is roughly a coin flip. |
| Operations | None. It deploys with your app because it is part of your app. | A PHP host, core and plugin updates, and a security surface to watch. |
| Ecosystem | Almost none. If you need a feature nobody wrote, you write it. | Enormous, and a real advantage. Whatever you need probably exists already. |
npm install @vinumcms/core @vinumcms/adapters \ @vinumcms/server @vinumcms/react @vinumcms/admin npx vinumcms doctor # checks the three settings that fail silentlyThe setup guide — install, wiring, the three build settings, and the eighteen theme variables.
The packages — core, server, react, admin, adapters, and mail if you send any.
Vinum is small on purpose. If it ever feels big, something has gone wrong.