Most teams don't set out to run five backends. It happens one product at a time: a shop needs an API, so it gets one. Then a CRM, then a booking tool, then something for tax. Each arrives with its own sign-in, its own user table, its own idea of roles and its own copy of the same security fixes. Two years in, a password policy change is five tickets and a customer who uses two products has two accounts.

OpsAPI takes the other route. There's one API with a shared core, and the business modules live behind it as switchable parts.

Three products with three of everything, compared with one OpsAPI core and switchable modulesA BACKEND PER PRODUCTShop appown sign-inown usersown databaseCRM appown sign-inown usersown databaseTax appown sign-inown usersown databaseONE OPSAPI, MODULES PER DEPLOYMENTShopCRMTaxOpsAPI coresign-in, users, roles, workspaces, webhooksOne PostgreSQLevery row tagged with its workspace
On the left, every product repeats sign-in, users and storage. On the right, products are modules on one core: a fix to sign-in or roles lands once.

What the core gives every module

  • Sign-in with passwords and emailed codes, Google and Apple, lockout and rate limits.
  • Workspaces: each customer or company is a workspace, and every record is kept apart by workspace.
  • Roles and permissions per workspace, down to read, create, update and delete per module.
  • API keys, webhooks, an audit trail and plugins, the same for every module.

A new module only has to describe its own data and rules. It inherits everything else, and so does every app built on it.

Modules are switched on per deployment

Not every customer should have every module. Each OpsAPI deployment sets one value, PROJECT_CODE, to a preset: business brings CRM, invoicing, accounting, timesheets and projects; ecommerce brings stores, orders, delivery and reviews; hospital brings patient and care management; core_only is just identity. Presets can be combined. A module that's switched off isn't hidden, it's absent: its addresses answer “not found” for everyone and its database tables are never created.

That gives you a simple way to sell and run tiers. A product line is a preset. A customer who must never touch a module gets a deployment without it. And the code stays one codebase, so a fix ships everywhere.

Why this pays off

  • Fewer moving parts. One service to patch, monitor and back up instead of one per product.
  • One person, one account. Customers and staff sign in once across products, with roles per workspace.
  • Faster new products. The tenth module costs less than the first because sign-in, roles and integrations are already there.
  • Integrations once. Webhooks, API keys and the TypeScript client work the same for every module, so partners integrate once.
  • Your infrastructure. It's open source and self-hosted, so data stays where you run it and there's no per-user fee.

What you still own

Self-hosting is a trade. You run a PostgreSQL database and take its backups. You upgrade OpsAPI when releases land; migrations run as part of a deploy, but they still need watching. You monitor it, and you secure the admin side, ideally behind a VPN or zero-trust access rather than on the open internet.

Honest limits

  • Module sets are per deployment, not per workspace. Two workspaces on the same deployment have the same modules available; roles and menus can hide one from members, but a hard split needs a separate deployment.
  • One codebase means shared releases. An upgrade touches every module on that deployment, so test the ones you use.
  • Not an off-the-shelf identity standard. OpsAPI's sign-in isn't an OpenID Connect or SAML provider; apps use its own redirect and token contract.
  • Some modules are specialised. UK tax filing or hospital care won't matter to most teams; that's exactly why they're switchable.

Where to go next

The modules map shows every module and preset. The live demo runs the smallest preset, identity only, with two apps signing in through it.