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.
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.
:3004, sales :3005, operation :3006…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.
# 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 65536git --version && brew --version && ulimit -ngit version 2.x, Homebrew 4.x, 65536
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 --systemgit --version && gcc --version | head -1 && cat /proc/sys/fs/inotify/max_user_watchesgit version 2.x, gcc 11+ or 13+, 524288
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.
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 22node -v && npm -vv22.x.x and 10.x.x
~/.zshrc only if that file already exists. Run touch ~/.zshrc, run the install line again, then open a new terminal.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.
npm install -g pnpm@9.12.3pnpm -v9.12.3
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.
# 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 animatingbrew install --cask orbstack) is a lighter drop-in alternative. It uses the same docker commands, so the rest of this step doesn't change.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 $USERb. Start MongoDB and Redis
Keep the infra compose file outside the erxes repo so it never ends up in a commit.
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 -d127.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.docker compose ps
docker exec erxes-mongo mongosh --quiet --eval 'db.runCommand({ ping: 1 })'
docker exec erxes-redis redis-cli pingboth containers "running", { ok: 1 }, PONG
MongoDB 8.0 and Redis with Homebrew
MongoDB's own tap also installs mongosh and the backup tools. brew services starts both at login.
brew tap mongodb/brew
brew install mongodb-community@8.0 redis
brew services start mongodb-community@8.0
brew services start redisbrew services list
mongosh --quiet --eval 'db.runCommand({ ping: 1 })'
redis-cli pingboth "started", { ok: 1 }, PONG
127.0.0.1 by default. Config lives in $(brew --prefix)/etc/mongod.conf and redis.conf.a. MongoDB 8.0 (official repo)
Ubuntu's own archive doesn't ship MongoDB, so add MongoDB's apt repo. The command picks jammy or noble automatically.
curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc \
| sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg --dearmor
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] \
https://repo.mongodb.org/apt/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME")/mongodb-org/8.0 multiverse" \
| sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
sudo apt update
sudo apt install -y mongodb-org
sudo systemctl enable --now mongodb. Redis
sudo apt install -y redis-server
sudo systemctl enable --now redis-serversystemctl is-active mongod redis-server
mongosh --quiet --eval 'db.runCommand({ ping: 1 })'
redis-cli pingactive, active, { ok: 1 }, PONG
127.0.0.1 by default. Leave bindIp in /etc/mongod.conf alone unless you add authentication first.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.
cd ~
git clone https://github.com/erxes/erxes.git
cd erxes
pnpm installpnpm nx show projects | head -20a list including core-api, gateway, core-ui, sales_api, sales_ui…
Configure .env
Every backend service and both dev scripts read the root .env. Start from the sample, then set the values below.
cp .env.sample .env
# Generate a JWT secret and paste it into .env
openssl rand -hex 32NODE_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| Variable | What it controls |
|---|---|
MONGO_URL | Database for every service. directConnection=true skips replica-set discovery on a single local node. |
REDIS_HOST / REDIS_PORT | Service discovery between the gateway and APIs, plus queues and pub/sub. Add REDIS_PASSWORD if your Redis has one. |
ENABLED_PLUGINS | Which 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_SERVICES | Optional background services, e.g. logs,automations. Undo/revert in System Logs needs logs. |
DOMAIN | Where the UI lives. Used for CORS and for links in emails. |
JWT_TOKEN_SECRET | Signs auth tokens. Use a random value and never commit it. |
.env out of gitIt already appears in .gitignore. Never paste real tokens into the sample file.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
pnpm dev:apisStarts 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:
🚀 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/graphqlpnpm dev:core-api instead. It starts just the core API and the gateway.Terminal 2: frontend
pnpm dev:uisGenerates 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.
Create the owner account
On an empty database erxes has no users, so the first visit sends you to the create-owner page.
- Open http://localhost:3001.
- Fill in your name, email and a password. This becomes the workspace owner with every permission.
- Sign in with the same credentials. Each plugin in
ENABLED_PLUGINSshows up in the left navigation.
ENABLED_PLUGINS and restart both terminals. No other change is needed.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.
# 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) 'Daily start / stop
| Task | Command |
|---|---|
| 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 backend | cd ~/erxes && pnpm dev:apis |
| Start frontend | cd ~/erxes && pnpm dev:uis |
| Stop erxes | Ctrl+C in both terminals |
| Stop databases (keeps data) | cd ~/erxes-infra && docker compose stop |
| Pull the latest code | git pull && pnpm install, then restart both terminals |
| Run a single service | pnpm nx serve sales_api or pnpm nx serve sales_ui |
| Back up the database | mongodump --uri="mongodb://localhost:27017/erxes" --out=~/erxes-backup-$(date +%F) |
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.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:
ss -tulpn | grep ':4000' # shows pid=12345
kill 12345lsof -nP -iTCP:4000 -sTCP:LISTEN # PID is the second column
kill 12345Port 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/_uisuffix. - Both terminals read
.envonly at start. Restart both after editing it. - Check Terminal 1 for that plugin's
🚀 … readyline. 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:
pnpm install
pnpm nx reset
pnpm nx build erxes-api-sharedThe 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.