Architecture
How the gateway, backend services, frontend host, and shared libraries fit together at runtime.
erxes is a single Nx/pnpm monorepo. On the backend, each service is an Express app that exposes an Apollo Federation subgraph; the gateway composes them into one supergraph behind a single public /graphql endpoint. On the frontend, one Module Federation host (core-ui) loads a remote per enabled plugin. MongoDB stores tenant data; Redis carries service discovery, session tokens, and every BullMQ queue.
Key concepts
- One public endpoint. The gateway on port
4000(main.ts) is the only service clients call. It proxies/graphqlto an Apollo Router it spawns on127.0.0.1:50000, forwards/pl:<name>to a plugin's own HTTP routes (webhooks, callbacks), and falls through to Core API for everything else. - Redis service discovery. Every backend registers
erxes-service-<name>(its address) anderxesservice:config:<name>(Mongo URL,meta, release version) through service-discovery.ts. The gateway waits forcoreplus every name inENABLED_PLUGINSbefore it composes the supergraph and starts listening. - Subdomain tenancy. The gateway derives the tenant from the request hostname; each service builds per-tenant Mongoose models from that subdomain, so the same code serves every organization.
- Module Federation frontend.
core-ui(port3001) loads<name>_ui/configfor each enabled plugin and builds routes, navigation, settings, and widgets from the exportedIUIConfig. In production the remote entries come from theplugins.erxes.ioCDN, not from your containers (see bootstrap.tsx). - Shared libraries with hard boundaries. Backend code uses
erxes-api-shared(utils,core-types,core-modulesentrypoints); frontend code useserxes-uiandui-modules, always through public exports, never another service's source. - Background services are not subgraphs.
logs(3301) andautomations(3302) are BullMQ workers the gateway never routes GraphQL to. Plugins reach them throughmetaregistrations and named<service>-<queue>queues on Redis.
Request flow
Browser ── HTTPS ──> Nginx ── /gateway/ ──> Gateway :4000
│ userMiddleware maps Bearer / app /
│ portal / agent credentials into
│ user, clientportal, cpuser headers
├─ /graphql ──> Apollo Router 127.0.0.1:50000
│ ├─> Core API :3300 (core subgraph)
│ └─> Plugin APIs :3303+ (subgraphs)
├─ /pl:<name> ──> plugin HTTP routes (webhooks)
└─ / ──> Core API routes
(/initial-setup, /get-frontend-plugins, ...)
Every service registers in Redis: erxes-service-<name>, erxesservice:config:<name>
BullMQ queues on Redis ──> logs-service :3301, automations-service :3302
core-ui :3001 host loads <name>_ui remotes via Module Federation
(production remote entries served from plugins.erxes.io)
Guides
Was this helpful?