DocsStart hereInstall Vinum

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

terminal
npx create-react-router@latest my-sitecd my-site

Accept 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

terminal
npx vinumcms init

This is the only step that is more than a package install, and it prints what it touched:

output
+  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

terminal
npx vinumcms doctor
output
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

terminal
npm run dev

Open /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.