Creating a frontend module
OpenMRS publishes @openmrs/create-o3-app, a generator for scaffolding O3 frontend modules. Module authors should run it through npm’s create initializer as npm create @openmrs/o3-app@latest. The generator source lives in openmrs/create-o3-app, and the Template frontend module remains useful as a reference for the generated structure.
Always include the @openmrs/ scope. The unscoped create-o3-app package on npm is an unrelated third-party project, so commands such as npx create-o3-app ... fetch the wrong tool. Use npm create @openmrs/o3-app@latest ... or npx @openmrs/create-o3-app@latest ....
Prerequisites
- Node.js 20 or newer.
- Corepack enabled, so the generated project’s pinned Yarn version works without a separate Yarn install. If Corepack is not enabled yet, run
corepack enableonce.
Quick start
Run the generator from the directory where the new module folder should be created:
npm create @openmrs/o3-app@latest active-prescriptionsThis creates a standalone page module using the CLI defaults. In directories where the CLI detects an existing monorepo, it may ask whether to add the module to that monorepo. If npm create is not your habit, the equivalent scoped npx command is:
npx @openmrs/create-o3-app@latest active-prescriptionsExample: active prescriptions
Suppose you want to create a frontend module that provides a UI for displaying active prescriptions. Our goal is to recreate the Active Prescriptions tab from openmrs-esm-dispensing-app.
Scaffold the module
For a repeatable, CI-friendly command, pass explicit flags after npm’s -- separator:
npm create @openmrs/o3-app@latest active-prescriptions -- \
--standalone \
--package-name "@openmrs/esm-active-prescriptions-app" \
--route "/active-prescriptions" \
--route-component "ActivePrescriptions" \
--no-git \
--quietThe -- separator is required when forwarding flags through npm create. Rspack is the default build tool; add --webpack only if you specifically need a Webpack scaffold.
Why the esm prefix? Frontend modules conventionally use package names that start with esm. See the frontend modules overview.
Run it locally
The generated directory is based on the package name. For the command above, enter the generated project and start the local O3 shell:
cd openmrs-esm-active-prescriptions-app
corepack yarn install
corepack yarn startFor standalone modules, the CLI installs dependencies automatically unless installation is skipped, interrupted, or you used --dry-run, but running corepack yarn install is safe when you are checking out or resuming a generated project. The app should be available at http://localhost:8080/openmrs/spa/active-prescriptions. Use username admin and password Admin123 for the default development backend.
Use corepack yarn start --port <port> for a different port. Use corepack yarn start --backend <url> to point the development shell at another OpenMRS backend, such as corepack yarn start --backend http://localhost.
Customize the generated files
Review the files most modules change first:
src/constants.tsexports the packagemoduleName.src/routes.jsonregisters pages and extensions with the app shell.src/config-schema.tsdefines runtime configuration.src/active-prescriptions.component.tsxis the generated page component.translations/en.jsoncontains the starter translation strings.
The generated module also includes src/index.ts, src/root.component.tsx, the selected build config (rspack.config.js by default), a starter src/root.component.test.tsx, Vitest with jsdom, ESLint, Prettier, Husky, and translation extraction wiring. src/routes.json maps the /active-prescriptions route to the exported root lifecycle, and root.component.tsx renders the route component. If you generate a module with extensions, the same template pattern creates extension component files and exports their lifecycles from src/index.ts.
Preview before writing files
Use --dry-run to see what would be created without writing files, installing dependencies, or initializing Git:
npm create @openmrs/o3-app@latest active-prescriptions -- --dry-runCommon flags
| Flag | Use |
|---|---|
--standalone | Create a standalone module, which is the default outside a detected monorepo. |
--monorepo | Add a module to the current monorepo and use the default package path. |
--new-monorepo | Create a new monorepo root with this module as its first package. |
--package-name <name> | Set the npm package name, such as @openmrs/esm-active-prescriptions-app. |
--route <route> | Set the route path for a page module. Use it with --route-component. |
--route-component <name> | Set the React component name for the page route. Use it with --route. |
--webpack | Use Webpack instead of the default Rspack build config. |
--no-git | Skip Git initialization. |
--no-ci | Reserved for generated CI workflow support. The current template accepts the flag but does not emit workflow files yet. |
--dry-run | Preview generated files without writing them. |
--quiet | Suppress output and use defaults where possible. |
--verbose | Print more detailed output. |
--rspack exists only as a deprecated compatibility flag because Rspack is already the default.
Monorepos
Existing monorepo
From the monorepo root, run:
npm create @openmrs/o3-app@latest referrals-queue -- --monorepoThe CLI uses the default package path packages/apps/esm-referrals-queue and updates the workspace configuration when it detects a supported workspace file.
New monorepo
To create a new monorepo root with the generated module as its first package, run:
npm create @openmrs/o3-app@latest referrals-workspace -- --new-monorepoThe CLI creates the root project and places the module under packages/apps/esm-referrals-workspace.
Publishing and adding to a distribution
Once the frontend module is ready, publish the package to npm. The package should then be visible on npmjs.com, such as @openmrs/esm-login-app.
To include the module in a distribution, add it to the frontendModules object in the distribution’s spa-assemble-config.json file:
{
"frontendModules": {
"@openmrs/esm-active-prescriptions-app": "1.0.0"
}
}Use a tested version for release distributions. For more information, see the Creating a distribution guide and the Configuration overview guide.