Getting started

Getting started

React versions

Devora.js supports React 18.3 and React 19 (peer range ^18.3.0 || ^19.0.0); new projects start on React 18. The roadmap records this as finding U11 (fixed in 0.3.2).

The quickest way to a working project is the create-devora installer. It works from an empty directory — you don't need a devora.config.ts or any framework files first.

npm create devora@latest

Yarn and pnpm work the same way: yarn create devora or pnpm create devora (npx create-devora@latest does too). You need Node 20 or newer. New projects depend on @devorajs/core and @devorajs/cli ^0.3.5 and start on React 18.

On a recent npm (11), the install can print a warning that esbuild's postinstall script is not yet covered by allowScripts; install, devora dev and devora build still work, and the warning comes from npm, not from Devora.js.

What it asks

Run with no flags in a real terminal, it prompts for four things in order:

1. Project name. Defaults to my-devora-app. This becomes the directory the CLI creates — it refuses to run if that directory already exists.

2. What do you need? full-stack (the default) generates page apps plus one shared backend, packages/backend. frontend generates page apps only, with no packages/backend at all. backend generates API-only apps — an endpoints/ folder of routes, served under /api, with no pages and no React — plus the shared backend. Either way a project gets at most one shared backend; logic only one app needs can live inside that app instead (see The shared backend pattern).

3. App names (comma-separated). Defaults to marketing,dashboard,admin (api for a backend-only project). Each name becomes one app under apps/ — this is where multi-app is decided. A single-app project just answers with one name; a project with a public site, a logged-in product, and an internal panel answers with three. You can add or remove apps later with devora add/devora remove, so this choice isn't permanent.

4. Auth mode, once per app. For each app name, it asks: "Does <app> need auth/sessions? [shared/isolated/none] (default: shared)". This is the per-app choice described in Core concepts — shared puts the app on the project's common login/session, isolated gives it its own separate sessions — its own cookie name and optionally its own secret, so a login to one app is never valid in the other (e.g. an admin panel with a different identity provider), and none disables sessions and CSRF for that app entirely (e.g. a marketing site with no login anywhere). A marketing-style app should answer none — it never generates a login route or expects a session secret.

Every prompt has a non-interactive fallback: running in a script or CI (no real TTY) skips straight to the defaults above, and --scope=fullstack|frontend|backend, --apps= and --auth=name:mode,... flags let you skip the prompts entirely while scripting a scaffold. --pm=npm|pnpm|yarn picks the package manager (otherwise it's the one you ran the installer with) and --skip-install only writes the files:

npm create devora@latest my-app -- --scope=fullstack --apps=site,app --auth=site:none,app:shared --pm=npm

Resulting project structure

For the default answers (full-stack, three apps, all shared auth), you get:

my-devora-app/
├── devora.config.ts        # declares every app + the project-wide auth default
├── package.json            # dev / dev:host / build / start / typecheck scripts
├── tsconfig.json, tsconfig.base.json
├── .env.example            # the session secrets production needs
├── packages/
│   └── backend/            # the shared backend — server functions + your DB client
│       └── db/index.ts     # stub: plug your own database in here
└── apps/
    ├── marketing/
    │   ├── routes/         # index.tsx, plus login/logout/account.tsx for an app with auth
    │   ├── error.tsx       # the app's 404 and error page
    │   ├── app.config.ts   # apiDir: "endpoints", sitemap, head
    │   ├── vite.config.ts
    │   ├── entry-server.tsx, island-client.tsx, csr-client.tsx
    │   ├── package.json, tsconfig.json
    │   └── vercel.json, netlify.toml
    ├── dashboard/          # same layout
    └── admin/              # same layout

Each app scaffolded with shared or isolated auth also gets a login.tsx/logout.tsx route pair and a protected demo route (account.tsx), wired up to the sessions described in Security model. An app scaffolded with none gets only index.tsx — no login routes, no session dependency. The assets/ folder (logo, favicon) and a few config files (pnpm-workspace.yaml, .gitignore, .npmrc, a README.md) sit at the project root too. API routes for a page app go in an endpoints/ folder you create when you need one (apiDir in app.config.ts); they're served under /api. Not api/: on Vercel a top-level api/ folder is Vercel's own functions folder (see Deployment).

A frontend project is the same minus packages/backend. A backend project has packages/backend and API-only apps instead:

my-devora-app/
├── devora.config.ts
├── package.json
├── packages/
│   └── backend/
│       └── db/index.ts
└── apps/
    └── api/
        ├── endpoints/      # health.ts, plus session.ts (token login/logout) and me.ts for an app with auth
        ├── app.config.ts   # backendOnly: true, apiDir: "endpoints"
        ├── vite.config.ts
        ├── package.json, tsconfig.json
        └── vercel.json, netlify.toml

Next steps: start the dev server

From inside the project, after the installer's dependency install has finished (or after you've run npm install yourself):

cd my-devora-app
npm run dev

That starts every app in dev mode and prints a short header with the CLI version and how long startup took, every app's URLs, then each app's routes (pages always; API routes listed up to 10 per app, counted above that). Ports start at 10000, one per app in devora.config.ts order. To run a single app, pass the flag through npm: npm run dev -- --app=dashboard. --routes lists every API route, --quiet prints only the URLs, warnings and errors, and npm run dev:host exposes the dev servers on your local network (with a warning). .env files in the project root are loaded automatically.

Why not just devora dev? The CLI is installed into the project (node_modules), not onto your system PATH — so a bare devora command isn't found. That's normal: Next.js, Vite, and most framework CLIs work exactly the same way. It also means every project runs the exact CLI version it pins. Your options:

CommandNotes
npm run devRecommended. Runs the project's dev script, which calls its own pinned CLI. It's what the installer prints, and it can never pick up the wrong package. Other commands are scripts too: npm run build, npm run start, npm run dev:host.
npx devora devAlso runs the project's own CLI, for any command without a script (e.g. npx devora list). Only inside the project, after npm install: anywhere else, npx looks up the npm package literally named devora, which is an unrelated third-party tool — decline if npx offers to install it.
npm install -g @devorajs/cliMakes a bare devora command available everywhere. A convenience tradeoff, not the recommended default: the global copy doesn't follow each project's pinned version, so it can drift out of sync with the CLI a given project was built and tested against.

See the CLI reference for every command, or go straight to Build your first feature for a complete worked example.