Twenty minutes, from an empty folder to a page you published yourself and can see on the public site. No prior Vinum knowledge assumed. Every command below was run start to finish before this was written.
What you need
Node, and nothing else. Vinum needs React Router v7 or v8 with SSR, Tailwind v4, and a runtime with Web Crypto — and a new React Router app already has all three, so there is nothing to arrange first.
1. Make an app
npx create-react-router@latest my-sitecd my-siteAccept the defaults. You get React Router 8, React 19, Tailwind 4 and Vite 8 — which is exactly the floor Vinum asks for.
2. Install Vinum
npx vinumcms initThis is the only step that is more than a package install, and it prints what it touched:
+ Packages Installed @vinumcms/core, adapters, server, react, admin.+ app/vinum.server.ts Store, media and auth wiring.+ app/entry.server.tsx From React Router's default, plus the import.~ app/routes.ts Spread vinumRoutes() after your own routes.~ vite.config.ts Added ssr.noExternal and optimizeDeps.include.~ app/app.css Added 3 line(s).~ tsconfig.json Added allowImportingTsExtensions.+ .env wrote .env with a generated secret and password.Three of those are build settings, and they are the reason the command exists rather than a paragraph of instructions. Vinum ships TypeScript with no build step, so your bundler has to compile it instead of externalising it, Tailwind has to scan it, and TypeScript has to tolerate its imports. Each one fails silently when missing — the app runs and something is quietly wrong.
`init` never overwrites a file you wrote, and running it twice does nothing the second time.
3. Check the things that fail quietly
npx vinumcms doctor✓ Vite SSR config vite.config.ts sets ssr.noExternal to cover @vinumcms/.✓ Dev pre-bundling vite.config.ts pre-bundles @vinumcms for dev.✓ Tailwind sources app/app.css scans @vinumcms/react and @vinumcms/admin.✓ tsconfig tsconfig.json sets allowImportingTsExtensions.✓ Registration app/vinum.server.ts is imported by app/entry.server.tsx.✓ Store app/vinum.server.ts uses a store that survives a restart.✓ Session secret SESSION_SECRET is set in .env. Nothing to fix.Run this any time the admin behaves strangely. It checks the settings whose absence produces a confusing symptom somewhere else entirely.
4. Start it and sign in
npm run devOpen /admin. Your email and password are in `.env`, generated during install — the password is random and the email is a placeholder, so change `ADMIN_EMAIL` before you put this anywhere.
5. Publish a page
In the admin, go to Pages → New page. Give it a title and the slug `hello`, then add a block or two by hovering the gap where you want one and clicking the +.
Type directly on the page — the canvas is the real page, not a preview of it. Set Status to Published in the page settings, then press Publish changes.
Now visit /hello. That is your page, served from your own store, on your own machine.
What you just built
An admin at `/admin`, pages at `/<slug>`, drafts and revisions, scheduled publishing, media, forms, redirects, a sitemap and search — inside the app you already had. Vinum added routes to your route tree; it did not take the app over.
Your content is in `data/store.json`. It is yours, it is on your disk, and `npx vinumcms export` writes the whole site to one file whenever you want it. Worth running now rather than later: an escape route you have not checked is not one.
Where to go next
Set a theme — eighteen `--vinum-*` variables decide how every block and the entire admin look. Then write a block of your own: a schema and a renderer, in your repo, through the same API the core blocks use.