Run OnERP locally
OnERP is a monorepo: an API, an admin app, a warehouse app, and this documentation site. One command starts them all.
Prerequisites
Section titled “Prerequisites”Node.js 22 or newer and pnpm 10 — the version is pinned in the root
package.json under packageManager, so corepack enable fetches it.
Postgres and Redis, running locally. Any recent Postgres works (Postgres.app,
Homebrew, Herd); the API needs a database to point at, and Cube — the analytics
engine the dashboard reads — queries that same database over the wire. Redis backs
the background jobs and the live updates between open tabs. Without Redis the API
and pnpm cli refuse to start with Connection is closed.
pnpm installcreatedb onerpcp apps/api/.env.example apps/api/.env # set DATABASE_URL to your Postgrescp apps/cube/.env.example apps/cube/.env # same database, same CUBEJS_API_SECRETpnpm build # workspace packages are consumed from dist/pnpm cli reset --demo # wipe, migrate, seed a Dev tenantpnpm devWhat runs
Section titled “What runs”pnpm dev starts every app in watch mode:
| Admin app | http://localhost:5173 |
| Warehouse app | http://localhost:5174 |
| API | http://localhost:3000 |
| This site | http://localhost:4330 |
| Inngest dev server | http://localhost:8288 |
| Cube (analytics) | http://localhost:4000 |
Nothing else needs starting. The development tools below are switches on the API rather than servers of their own.
Cube is the analytics engine, and clients query it directly rather than through
the API: GET /api/analytics/access returns Cube’s address and a token scoped to
the signed-in tenant. Cube’s Playground is on http://localhost:4000 — set a
security context of { "tenantId": "…", "modelVersion": "…" } there before running a
query, because the compiled data model is per tenant.
await client.cube() returns the authenticated Cube client. React applications
query it with useCubeQuery from @onerp/react/data. Dashboard totals come from
Cube; record previews use the list API. The dashboard loads totals when opened
and does not poll for changes.
Signing in
Section titled “Signing in”Open http://localhost:5173:
email: dev@onerp.devpassword: dev-passwordtenant: DevThe warehouse app takes the same credentials.
What reset does
Section titled “What reset does”pnpm cli reset drops every schema in the configured database, re-runs the
migrations, and creates a tenant called Dev. It prompts before wiping anything;
pass --yes to skip the prompt.
The tenant is born with its base seed data, the same set a real signup gets: the payment term Net 30, number series for sales orders and sales invoices, a profile called Default with no company yet, the Quality Inspection and Blocked stock restrictions, and every EU country’s VAT rates with the Standard / Reduced / Exempt classifications.
Units of measure are a code list rather than records, so nothing seeds them. No locations are seeded, and no stock can move until some exist.
--demo adds a sample dataset on top: business partners, product types, categories
and products, sales prices, sales orders, a warehouse hierarchy with bins, and stock
booked into it. The user guides are written against that dataset.
Development tools
Section titled “Development tools”Every optional piece is a line in apps/api/.env, documented in
apps/api/.env.example. Set it, restart pnpm dev:
Set in apps/api/.env |
What it gives |
|---|---|
DATABASE_LOG_QUERIES=true |
every SQL statement, with duration and parameters, in the API log |
NEST_DEVTOOLS=true |
the dependency graph, routes with their guard chains, and bootstrap timings, served on :8000 for Nest Devtools. Structural only — no requests, no queries |
AI_DEVTOOLS=true |
agent tool calls, model input and output, and token usage. Run pnpm ai:devtools alongside and open http://localhost:4983 |
ANTHROPIC_API_KEY= or OPENAI_API_KEY= |
the assistant in the admin sidebar. Without one it errors when opened |
MAIL_PREVIEW=true |
outgoing mail opens in the browser instead of reaching an SMTP server. On by default |
Request traffic needs nothing enabled — read it in the browser’s Network tab.
The end-to-end suite
Section titled “The end-to-end suite”pnpm e2e starts its own API, Cube and web servers on separate ports and wipes
its database on every run, so it never shares one with development: create
onerp_e2e once (createdb onerp_e2e) and the suite derives the connection from
DATABASE_URL in apps/api/.env, or set E2E_DATABASE_URL outright.
The unit-test harness is the one place PGlite (Postgres in WebAssembly) still runs;
the API accepts DATABASE_DRIVER=pglite for it, and nothing that needs Cube works
there.
Commands
Section titled “Commands”| Command | What it does |
|---|---|
pnpm dev |
every app in watch mode |
pnpm cli reset --demo |
wipe, migrate and reseed the Dev tenant |
pnpm test |
the test suites |
pnpm e2e |
Playwright journeys |
pnpm type-check · pnpm lint · pnpm format |
run all three before pushing |
pnpm docs:screenshots |
regenerate the guide screenshots from the real app |
Your first resource takes one business object from schema to a working list and form.