From a blank machine to localhost:3001

Run erxes locally, from zero

Install Node, pnpm, MongoDB and Redis, then boot the gateway, core API, plugin APIs and the web UI. Each step ends with a command that proves it worked, so you know where it broke if something fails.

~40 min first run 8 GB RAM min · 16 GB better ~10 GB free disk Ubuntu 22.04+ or macOS 13+
Commands below change to match your system.
Jump to a step
  1. What you'll run
  2. System packages
  3. Node.js 22
  4. pnpm 9.12.3
  5. MongoDB + Redis
  6. Clone & install
  7. Configure .env
  8. Start erxes
  9. Create the owner
  10. Health checks
  11. Daily start / stop
  12. Troubleshooting
01

What you'll run

erxes is an Nx + pnpm monorepo. The backend is a set of Node services that register with a gateway through Redis; the frontend is a React host that loads each plugin's UI over Module Federation. Locally, all of it runs from two terminals.

Browser
Core UI :3001React host. Open this in your browser. Plugin UIs are loaded into it: frontline :3004, sales :3005, operation :3006…
API
Gateway :4000Single GraphQL entry point. Discovers services through Redis and federates their schemas.
Core API :3300Users, contacts, products, segments, automations
frontline_api :3304Inbox, tickets, integrations
sales_api :3305Deals, pipelines, POS
Data
MongoDB :27017All business data
Redis :6379Service discovery, cache, BullMQ queues, pub/sub
Elasticsearch :9200Optional. Not needed for a basic local run.
02

System packages

Git to clone the repo, build tools for native npm modules, and a higher file-watcher limit. Nx and Rspack watch tens of thousands of files, and Ubuntu's default limit runs out.

Apple's command line tools give you git and a compiler for native npm modules. Homebrew installs everything else, including MongoDB and Redis in step 05. Works the same on Apple Silicon and Intel Macs.

zsh
# Git, clang, make (a dialog opens; click Install)
xcode-select --install

# Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# Apple Silicon only: put brew on your PATH (the installer prints this too)
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"

# Raise the open-file limit for the dev servers, in every new terminal
echo 'ulimit -n 65536' >> ~/.zshrc
ulimit -n 65536
verify
git --version && brew --version && ulimit -n

git version 2.x, Homebrew 4.x, 65536

terminal
sudo apt update && sudo apt upgrade -y
sudo apt install -y git curl wget ca-certificates gnupg build-essential python3

# Let the dev servers watch the whole monorepo
echo "fs.inotify.max_user_watches=524288" | sudo tee /etc/sysctl.d/99-erxes-watchers.conf
echo "fs.inotify.max_user_instances=1024" | sudo tee -a /etc/sysctl.d/99-erxes-watchers.conf
sudo sysctl --system
verify
git --version && gcc --version | head -1 && cat /proc/sys/fs/inotify/max_user_watches

git version 2.x, gcc 11+ or 13+, 524288

03

Node.js 22 with nvm

erxes CI builds on Node 22. Install it through nvm rather than apt or brew so you never need sudo for global packages and can switch versions per project.

terminal
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash

# Load nvm into this shell (new terminals load it automatically)
export NVM_DIR="$HOME/.nvm"
. "$NVM_DIR/nvm.sh"

nvm install 22
nvm alias default 22
verify
node -v && npm -v

v22.x.x and 10.x.x

"nvm: command not found" on macOS?The installer writes to ~/.zshrc only if that file already exists. Run touch ~/.zshrc, run the install line again, then open a new terminal.
Already have Node 18+?The README accepts Node 18 or newer, and newer releases like 23 also run it. Node 22 matches CI, so if something only breaks on your machine, check this version first.
04

pnpm 9.12.3

The repo pins "packageManager": "pnpm@9.12.3" and blocks npm and yarn. Use the same version so pnpm-lock.yaml resolves the same way.

terminal
npm install -g pnpm@9.12.3
verify
pnpm -v

9.12.3

05

MongoDB + Redis

Pick one approach. Docker keeps your OS clean and makes it easy to wipe or upgrade the databases. Native packages (aptHomebrew) start faster and use less RAM.

a. Install Docker

Skip this if docker -v already prints a version.

zsh
# Docker Desktop (free for personal use and small companies)
brew install --cask docker
open -a Docker   # wait until the whale icon in the menu bar stops animating
OrbStack (brew install --cask orbstack) is a lighter drop-in alternative. It uses the same docker commands, so the rest of this step doesn't change.
terminal
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
  | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# Run docker without sudo (log out and back in afterwards)
sudo usermod -aG docker $USER

b. Start MongoDB and Redis

Keep the infra compose file outside the erxes repo so it never ends up in a commit.

terminal
mkdir -p ~/erxes-infra && cd ~/erxes-infra

cat > docker-compose.yml <<'EOF'
services:
  mongo:
    image: mongo:7
    container_name: erxes-mongo
    restart: unless-stopped
    ports:
      - "127.0.0.1:27017:27017"
    volumes:
      - mongo-data:/data/db

  redis:
    image: redis:7-alpine
    container_name: erxes-redis
    restart: unless-stopped
    ports:
      - "127.0.0.1:6379:6379"
    volumes:
      - redis-data:/data

volumes:
  mongo-data:
  redis-data:
EOF

docker compose up -d
Keep the 127.0.0.1: prefix on the portsDocker writes its own iptables rules and bypasses ufw. Without the prefix, an unauthenticated MongoDB and Redis are reachable from your whole network.
verify
docker compose ps
docker exec erxes-mongo mongosh --quiet --eval 'db.runCommand({ ping: 1 })'
docker exec erxes-redis redis-cli ping

both containers "running", { ok: 1 }, PONG

06

Clone and install dependencies

One pnpm install at the root installs every backend service, plugin and UI in the workspace. Expect 5–15 minutes and a few GB in node_modules the first time.

terminal
cd ~
git clone https://github.com/erxes/erxes.git
cd erxes
pnpm install
verify
pnpm nx show projects | head -20

a list including core-api, gateway, core-ui, sales_api, sales_ui…

07

Configure .env

Every backend service and both dev scripts read the root .env. Start from the sample, then set the values below.

terminal · in ~/erxes
cp .env.sample .env

# Generate a JWT secret and paste it into .env
openssl rand -hex 32
.env · minimum working config
NODE_ENV=development

# Data
MONGO_URL=mongodb://localhost:27017/erxes?directConnection=true
REDIS_HOST=localhost
REDIS_PORT=6379

# URLs
DOMAIN=http://localhost:3001
ALLOWED_DOMAINS=http://localhost:3001,http://localhost:4000
REACT_APP_API_URL=http://localhost:4000

# Plugins to boot: each name maps to backend/plugins/<name>_api and frontend/plugins/<name>_ui
ENABLED_PLUGINS=frontline,sales

# Paste the output of: openssl rand -hex 32
JWT_TOKEN_SECRET=replace-with-your-random-64-char-hex

# Give each Node process enough heap for the TypeScript build
NODE_OPTIONS=--max-old-space-size=1536
VariableWhat it controls
MONGO_URLDatabase for every service. directConnection=true skips replica-set discovery on a single local node.
REDIS_HOST / REDIS_PORTService discovery between the gateway and APIs, plus queues and pub/sub. Add REDIS_PASSWORD if your Redis has one.
ENABLED_PLUGINSWhich plugin APIs dev:apis starts and which UIs dev:uis loads. Available: frontline, sales, operation, content, accounting, loyalty, payment, insurance, tourism, mongolian, posclient. Each one costs roughly 0.5–1 GB of RAM.
ENABLED_SERVICESOptional background services, e.g. logs,automations. Undo/revert in System Logs needs logs.
DOMAINWhere the UI lives. Used for CORS and for links in emails.
JWT_TOKEN_SECRETSigns auth tokens. Use a random value and never commit it.
Keep .env out of gitIt already appears in .gitignore. Never paste real tokens into the sample file.
08

Start erxes

Use two terminals, both in ~/erxes. Start the backend first so the gateway is ready when the UI asks for its schema.

Terminal 1: backend

terminal
pnpm dev:apis

Starts core-api, gateway and every <plugin>_api listed in ENABLED_PLUGINS. The first boot compiles TypeScript, so give it 1–3 minutes. It's ready when each service has printed a line like:

expected output
🚀 core graphql api ready at http://localhost:3300/graphql
🚀 sales graphql api ready at http://localhost:3305/graphql
🚀 frontline graphql api ready at http://localhost:3304/graphql
To debug only the core, run pnpm dev:core-api instead. It starts just the core API and the gateway.

Terminal 2: frontend

terminal
pnpm dev:uis

Generates the GraphQL types for the enabled plugin UIs, then serves core-ui on :3001 with each plugin UI as a dev remote. Wait for Rspack to print compiled successfully.

09

Create the owner account

On an empty database erxes has no users, so the first visit sends you to the create-owner page.

  1. Open http://localhost:3001.
  2. Fill in your name, email and a password. This becomes the workspace owner with every permission.
  3. Sign in with the same credentials. Each plugin in ENABLED_PLUGINS shows up in the left navigation.
You're running erxes.To add a plugin later, append it to ENABLED_PLUGINS and restart both terminals. No other change is needed.
10

Health checks

Run these from a third terminal when something looks off. Work from the bottom layer up: if Redis fails, nothing above it will work.

terminal
# Data layer
redis-cli ping                                   # or: docker exec erxes-redis redis-cli ping
mongosh --quiet --eval 'db.runCommand({ping:1})' # or: docker exec erxes-mongo mongosh ...

# Services
curl -s http://localhost:3300/health; echo   # core-api
curl -s http://localhost:4000/health; echo   # gateway
curl -s http://localhost:3305/health; echo   # sales_api
curl -s http://localhost:3304/health; echo   # frontline_api

# What is listening on the erxes ports?
ss -tulpn | grep -E ':(3001|3300|3304|3305|4000|6379|27017)\b'lsof -nP -iTCP -sTCP:LISTEN | grep -E ':(3001|3300|3304|3305|4000|6379|27017) '
11

Daily start / stop

TaskCommand
Start databases (Docker)cd ~/erxes-infra && docker compose up -d
Start databases (native)Already on at bootlogin. Check: systemctl is-active mongod redis-serverbrew services list
Start backendcd ~/erxes && pnpm dev:apis
Start frontendcd ~/erxes && pnpm dev:uis
Stop erxesCtrl+C in both terminals
Stop databases (keeps data)cd ~/erxes-infra && docker compose stop
Pull the latest codegit pull && pnpm install, then restart both terminals
Run a single servicepnpm nx serve sales_api or pnpm nx serve sales_ui
Back up the databasemongodump --uri="mongodb://localhost:27017/erxes" --out=~/erxes-backup-$(date +%F)
Don't use docker compose down -vThe -v flag deletes the Mongo and Redis volumes, which means every workspace, user and record. Use stop or a plain down.
12

Troubleshooting

The failures people hit most on a first run, from the bottom of the stack up.

ECONNREFUSED 127.0.0.1:6379 or :27017

Redis or Mongo isn't running. Check with docker compose ps in ~/erxes-infra, or systemctl status mongod redis-serverbrew services list, then start it and restart pnpm dev:apis.

EADDRINUSE: port already in use

An old dev process is still holding the port. Find it, then stop it:

terminal
ss -tulpn | grep ':4000'        # shows pid=12345
kill 12345
terminal
lsof -nP -iTCP:4000 -sTCP:LISTEN   # PID is the second column
kill 12345

Port 5000 or 7000 taken on a Mac is AirPlay Receiver, not erxes. Turn it off in System Settings → General → AirDrop & Handoff if a custom plugin needs those ports.

JavaScript heap out of memory

Raise the heap in .env to NODE_OPTIONS=--max-old-space-size=3072, or enable fewer plugins in ENABLED_PLUGINS. With 8 GB of RAM, keep it to one or two plugins.

ENOSPC: System limit for number of file watchers reached

You skipped the inotify limit in step 02. Run that block again, then restart pnpm dev:uis.

EMFILE: too many open files

macOS allows only 256 open files per shell by default. Run ulimit -n 65536 in both terminals, or add it to ~/.zshrc as in step 02, then restart the dev servers.

Docker is slow or the Mac runs out of memory

Docker Desktop reserves a fixed slice of RAM for its VM. Lower it in Docker Desktop → Settings → Resources (2–4 GB is plenty for Mongo and Redis), or switch to the Homebrew tab in step 05 and skip Docker entirely.

The UI loads but a plugin is missing from the navigation
  • Check that the plugin name is in ENABLED_PLUGINS, spelled the way the folder is, without the _api / _ui suffix.
  • Both terminals read .env only at start. Restart both after editing it.
  • Check Terminal 1 for that plugin's 🚀 … ready line. If it crashed, the error is printed just above where it stopped.
CORS error or "Failed to fetch" in the browser console

The UI origin isn't allowed by the API. Make sure DOMAIN=http://localhost:3001, add the origin to ALLOWED_DOMAINS, and use localhost rather than 127.0.0.1 in the address bar, because the browser treats them as different origins.

ERR_PNPM_BAD_PM_VERSION or install fails with npm/yarn

The repo only accepts pnpm. Run npm install -g pnpm@9.12.3, then run pnpm install again.

Strange build errors after git pull

Clear the Nx cache and rebuild the shared backend library:

terminal
pnpm install
pnpm nx reset
pnpm nx build erxes-api-shared
The create-owner page doesn't appear and login rejects every user

You're probably pointing at a database that already has users, for example an old erxes database. Check with mongosh erxes --eval 'db.users.countDocuments()'. To start fresh without deleting anything, point MONGO_URL at a new database name such as /erxes_dev.