The open-source mobile, web and desktop apps for Resgrid — computer-aided dispatch (CAD), personnel, unit and incident management for fire departments, EMS, search and rescue, emergency management and any team that responds to events.
Five apps — Responder, Unit, IC, Dispatch and BigBoard — from one codebase, for iOS, Android, the web and Windows, macOS and Linux.
Note
Just want to use the apps? You don't need anything from this repository. Get the app from your app store or open it in your browser, and sign in with your Resgrid account.
Project status: the code for all five apps is complete and being verified on devices. Until an app's first Omni build is published, the version in the stores still comes from that app's original repository (Responder, Unit, IC, Dispatch, BigBoard). Bugs and requests for every app are welcome here either way. Progress is tracked in docs/implementation-status.md.
- What is Resgrid?
- The Apps
- Using the Apps
- Getting Help
- Features
- Run It Yourself
- Self-Hosting and Deployment
- How the Code Is Organized
- Contributing
- Roadmap
- FAQ
- License
Resgrid is an open-source platform for organizations that respond to emergencies and events: volunteer and career fire departments, EMS agencies, search and rescue teams, CERT, emergency management offices, industrial and campus response teams, and more. It handles dispatching calls, alerting and messaging members, tracking who is available and where units are, running incidents, scheduling shifts and keeping records.
Resgrid has two halves:
- Resgrid Core — the server, API and the resgrid.com web application. Use the hosted service or run it yourself.
- Resgrid Omni (this repository) — the client apps people carry, mount in vehicles, sit at, or put on the station wall. Every app talks to Resgrid Core.
| App | Who it's for | What it does | Get it | |
|---|---|---|---|---|
| Responder | Department members | Get dispatched and respond, set your status and staffing, read call details, message and chat, manage shifts and trades, calendar, checklists, work orders and certifications | App Store · Google Play · Web | |
| Unit | Apparatus, vehicle and team crews | A mobile data terminal (MDT) for vehicle tablets and laptops: unit status, crew roles, automatic vehicle location, push-to-talk, turn-by-turn navigation, routes and stops, inventory | App Store · Google Play · Web | |
| IC | Incident commanders | A digital command board for tablets and desktops: ICS structure, resource tracking, accountability and PAR, objectives, timers and command maps | Google Play | |
| Dispatch | Dispatchers | A multi-panel dispatch console: create and dispatch calls, pending, scheduled and archived call queues, run cards, unit and personnel actions, weather alerts | Web | |
| BigBoard | Stations and EOCs | A wall-display dashboard: active calls, units with status timers, personnel, maps, weather and alerts, in a layout you configure | Web |
Every app is built for iOS, Android, the web and desktop (Windows, macOS, Linux). Once an app moves to Omni, its desktop installers and a self-hostable Docker image are published with each GitHub Release.
- Get a Resgrid account. Your department, agency or team signs up at resgrid.com, then adds its members, units and groups. If your organization already uses Resgrid, ask your administrator for an account.
- Install the app you need from the table above, or open its web version.
- Sign in with your Resgrid username and password, or with your organization's single sign-on.
- Using your own Resgrid server? On the sign-in screen, choose Change Server URL and enter your server's address.
How-to guides for every part of Resgrid are in the Resgrid documentation and the Resgrid Help Center.
First, find out which app and version you have. The app's name is on its icon and in Settings → About → App Name; the same screen shows the Version with the build number in brackets, for example Version 8.12 (100012). Include both whenever you ask for help.
| You need help with… | Go to |
|---|---|
| Every app stopped working or cannot connect | Resgrid system status |
| Your account, billing, subscription or department setup | Resgrid Help Center or contact Resgrid |
| Something in an app is broken | Report a bug |
| An idea for a new feature or a change | Request a feature |
| How an app works, or building it from this repository | Ask a question |
| Telling us what works well or what is hard to use | Share feedback |
| Wrong or untranslated text | Report a translation problem |
| The resgrid.com website or the API | Resgrid Core issues |
| A security vulnerability | The security policy — never a public issue |
Every issue form asks which app (and platform) the issue is about, and the issue is labelled automatically, so it reaches the people who work on that app. Before opening a new issue, check whether someone has already reported it — add a 👍 to an existing issue instead of a "+1" comment.
| App | Known issues | Usually runs on |
|---|---|---|
| Responder | Open issues for Responder | Phones |
| Unit | Open issues for Unit | Vehicle tablets and laptops (MDT) |
| IC | Open issues for IC | Tablets and desktops |
| Dispatch | Open issues for Dispatch | Desktops and the web |
| BigBoard | Open issues for BigBoard | Wall displays and TVs |
| All apps | Issues affecting every app |
You can narrow any search by platform too, for example label:"platform: android" or label:"platform: ios".
Warning
Issues are public. Never include passwords, tokens, personal details of members, patients or callers, call addresses or notes, or anything your organization treats as protected. Blur them in screenshots.
Bugs seen when the apps connect to a self-hosted Resgrid Core server are welcome here (choose Self-hosted Resgrid Core in the bug form). Help installing or running your own server is not provided through GitHub — contact Resgrid. More detail is in SUPPORT.md.
Shared by all five apps:
- Works offline — the shift's working data is kept on the device. Actions taken without a connection are queued, survive restarts and are sent exactly once when the connection returns.
- Offline maps — MapLibre maps everywhere, with downloadable base maps and your department's own map data (custom and indoor maps, layers, POIs, hydrants) for its response area.
- Live updates — calls, statuses, units, personnel locations, incident command, chat and weather alerts update in real time.
- Notifications — push notifications on mobile, web and desktop, with critical alerts for dispatches and a notification inbox.
- Push-to-talk voice — with Bluetooth and headset PTT buttons where the app needs them.
- Turn-by-turn navigation — built into Unit, with live ETAs shown to dispatchers and on the BigBoard.
- Secure sign-in — multi-factor authentication, passkeys and single sign-on (OIDC/SAML), shared-device sessions for vehicles and consoles, protected data handling.
- Fits your organization — department terminology (rename calls, units, record types…), custom statuses, permissions and feature flags are honoured everywhere.
- Ten languages — English, Arabic, German, Greek, Spanish, French, Italian, Polish, Swedish and Ukrainian.
- Quick fixes — fixes ship as over-the-air updates without waiting for an app store review.
You only need this section if you want to run the apps from source, change them or contribute.
- Node.js 22.18 or newer and pnpm 10.5 or newer (
corepack enablegives you the version this repository pins) - Git
- For iOS: macOS with Xcode. For Android: Android Studio with JDK 17. Neither is needed for the web or desktop apps.
- A Resgrid account — on the hosted service or your own Resgrid Core server
git clone https://github.com/Resgrid/Omni.git
cd Omni
corepack enable
pnpm installOne project builds all five apps. The APP_VARIANT environment variable chooses which one: responder, unit, ic, dispatch or bigboard.
Each app has one command per platform. The quickest way to see an app is the web version — no Xcode or Android Studio needed. It starts the dev server and opens the app at http://localhost:8081:
pnpm web:dispatchOn iOS or Android, the command builds a development build, installs it on a simulator, emulator or connected device, and starts the dev server:
| App | Web | iOS | Android |
|---|---|---|---|
| Responder | pnpm web:responder |
pnpm ios:responder |
pnpm android:responder |
| Unit | pnpm web:unit |
pnpm ios:unit |
pnpm android:unit |
| IC | pnpm web:ic |
pnpm ios:ic |
pnpm android:ic |
| Dispatch | pnpm web:dispatch |
pnpm ios:dispatch |
pnpm android:dispatch |
| BigBoard | pnpm web:bigboard |
pnpm ios:bigboard |
pnpm android:bigboard |
pnpm ios:responder --device--devicelets you pick the simulator, emulator or connected phone; any otherexpo runoption works too. With npm, put--first:npm run ios:responder -- --device.- The web commands take any
expo startoption, such as--port 8082or--clear. - The five apps share one generated
apps/omni/iosandapps/omni/androidfolder. When it holds another app, or the app config changed, the command prebuilds it again first (a few minutes on iOS).--cleanforces that. - One dev server serves one app. On iOS or Android, if another app's dev server is running, stop it or add
--port 8082. On the web, Expo offers the next free port, so several apps can run side by side. - On a physical iPhone, set
IOS_APPLE_TEAM_IDto your Apple developer team ID so the build can be signed.
As a desktop app (start the web version first with pnpm web:bigboard, then in a second terminal):
APP_VARIANT=bigboard pnpm --filter @resgrid/desktop devTip
- Windows PowerShell: set the variable first, for example
$env:APP_VARIANT = "unit", then run the command without theAPP_VARIANT=…prefix. - Expo Go is not supported — the apps use native modules, so run them with the commands above.
- Switched apps and still see the old one? Stop the dev server and start it again with
--clear.
Every build, development included, connects to Resgrid's production US West server (https://api.resgrid.com) unless BASE_API_URL names another one. That is deliberate: a build or deployment that lost its variables still reaches the server members use, and never sends their sessions to QA. To work against QA or your own server, set BASE_API_URL before starting the app, or use Change Server URL on the sign-in screen:
BASE_API_URL=https://qaapi.resgrid.dev pnpm web:unitOn the web, the dev server passes the app's server requests on for it (apps/omni/metro/dev-api-proxy.js): a page on http://localhost:8081 is on no Resgrid server's CORS allowlist, so the browser would refuse the responses. Any server works without changing its CORS settings. Live updates (SignalR) use Server-Sent Events there, because the dev server carries no WebSockets. Web exports and the desktop app call the servers directly.
.env files are not read; set variables in your shell. The full list of settings (API paths, hub names, Sentry, Countly) is in docker/README.md — each one also works as an environment variable at development time.
Push notifications on iOS and Android need the app's Firebase files (google-services.json, GoogleService-Info.plist), which are not in this repository. Without them the apps still build and run; they just don't receive push.
pnpm test # Jest unit and component tests
pnpm lint # ESLint (zero warnings)
pnpm lint:anti-slop # Oxlint anti-slop rules: no file may gain a finding over tooling/oxlint/anti-slop-baseline.json (--prune after fixing some)
pnpm type-check # TypeScript
pnpm i18n:check # translation keys match across all ten languages
pnpm e2e:web # Playwright tests against the web builds
pnpm check-all # every check CI and the pre-commit hook run, with a pass/fail summary at the endpnpm check-all also builds each variant's web export and runs Playwright against it, which is the slow part. --quick skips those steps, --variants unit,ic limits the per-variant steps, --skip jest,e2e leaves steps out, --bail stops at the first failure and --list shows the step ids.
Each app has a multi-architecture (amd64, arm64) image — resgridllc/responder, resgridllc/unit, resgridllc/ic, resgridllc/dispatch, resgridllc/bigboard — configured with environment variables when the container starts:
docker run -d -p 8080:80 -e BASE_API_URL="https://api.example.com" resgridllc/unit:latestThe variable names used by the original images (such as UNIT_BASE_API_URL) keep working. Every setting, Docker Compose, health checks and passkey/app-link files: docker/README.md.
cd apps/omni && APP_VARIANT=unit APP_ENV=production pnpm web:exportThe output in apps/omni/dist/unit can be served by any web server or CDN that falls back to index.html for unknown routes.
One command per operating system builds the app's web export and packages it. Run each on that operating system, as the release builds do (macOS installers need a Mac):
APP_ENV=production pnpm desktop:mac unit # DMG and ZIP, x64 and arm64
APP_ENV=production pnpm desktop:windows unit # NSIS installer and portable exe
APP_ENV=production pnpm desktop:linux unit # AppImage, deb and rpmThe installers land in apps/desktop/release/unit. Name several apps to build them in turn (pnpm desktop:mac unit dispatch); --dir writes only the unpacked app, for a quick check. To package a web export you already have, without building it again: pnpm --filter @resgrid/desktop build --variant unit --mac.
Store builds use EAS Build with one profile per app and environment (for example unit-production). To publish your own copy you need your own app identity — see the FAQ.
Signing credentials stay on each app's EAS project. pnpm credentials:android unit, pnpm credentials:ios unit and pnpm credentials:ios-adhoc unit open eas credentials for one app's Android keystore, App Store or ad-hoc signing; --setup creates whatever is missing or expired. Details: docs/build/ci-secrets.md.
Official releases are built by GitHub Actions: each app gets its own GitHub Release (tags such as unit-v8.12) with every file and a SHA256SUMS. Build and release details: omni-plan §6.
apps/
omni/ the one Expo project (iOS, Android, web)
variants/
responder/ variant.json (identity + capabilities) · variant.ts · app/ (routes) · assets/
unit/ ic/ dispatch/ bigboard/
desktop/ Electron shell that packages each app's web build
packages/ shared code as @resgrid/* workspace packages
config core models api offline auth data realtime notifications
location voice maps navigation i18n ui app-shell features config-plugins
docker/ nginx image for the web apps
docs/ architecture, build and subsystem documentation
- One project, five apps. Each app's manifest (
apps/omni/variants/<app>/variant.json) holds what makes it that app: name, bundle ids, icons, URL schemes, the native modules and permissions it needs, its navigation and its capabilities. - Capabilities, not copies. Screens are shared. An app turns behaviour on or off with capabilities such as
calls.createorincidentCommand: 'command', and layouts adapt to the form factor (phone, tablet, desktop, wall display). - Layered packages. Lower layers never import higher ones (
config→core→api→auth… →features→app-shell→ apps); CI enforces it.
Tech stack: Expo SDK 58 · React Native 0.88 (New Architecture) · React 19 · TypeScript · Expo Router · Zustand · MMKV + SQLite · Axios · gluestack-ui + NativeWind / Tailwind CSS · MapLibre · SignalR · Novu + Notifee · LiveKit · Sentry · Electron · pnpm workspaces · Jest + Testing Library · Playwright.
The full design is in the consolidation plan.
Contributions are welcome — bug reports, translations, documentation and code.
- Found a problem or have an idea? Open an issue; see Getting Help for which form to use.
- Translations: all user-visible text is translated into ten languages. Corrections are very welcome through the translation form or a pull request.
- Code: fork the repository, branch from
developand open a pull request againstdevelop(masteris the release branch). Every change ships with tests, and CI runs lint, type-check, Jest, translation parity, dependency rules, API contract tests and per-app route checks. - Read AGENTS.md first. It is the short guide to conventions, layering and the rules that protect existing installs (bundle ids, storage identity, URL schemes). It is also the guide for AI coding agents, alongside the skills in
.claude/skills. - Changes to the server or API belong in Resgrid Core.
- Consolidation plan, agent guide and skills
- Phase 0 — repository scaffold, variant system, build pipeline
- Phase 1 — shared platform: API, sign-in, offline storage and sync, live updates, notifications, location, voice, over-the-air updates
- Phase 2 — app shells for every form factor
- Phase 3 — shared features (calls, contacts, chat, records, maps, offline maps…)
- Phase 4 — each app's own modules: BigBoard, IC, Dispatch, Unit, Responder (code complete)
- Device verification, upgrade testing from the current store apps, beta and store releases — one app at a time
- Phase 5 — MapLibre follow-ons as their server work lands
- Phase 6 — hardening (Electron auto-update rollout, CI time)
Details and open items: docs/implementation-status.md.
- Do I need to build anything to use Resgrid?
- No. Install the apps from the app stores or use the web versions, and sign in with your Resgrid account. This repository is for people who want to run, change or contribute to the apps.
- Do the apps work with a self-hosted Resgrid server?
- Yes. Choose Change Server URL on the sign-in screen. Self-hosted installs can also serve their own map tiles, routing and geocoding (see the Resgrid docs).
- Can I publish these apps to Google Play or the Apple App Store myself?
- You can, but you cannot use "Resgrid" in the name of your app or its store listing.
- What do I need to change to publish my own build?
- Edit the app's identity in
apps/omni/variants/<app>/variant.json(name, bundle id, package, URL schemes, associated domains, EAS project) and replace the icons, logos and splash images in that app'sassets/folder. Nothing outside the variant folder should need to change.
- Edit the app's identity in
- Why one repository for five apps?
- The apps started from one shared scaffold and were copied for each audience. Over time the copies drifted: the same fix had to be made five times, and features reached some apps but not others. Omni brings them back together — one codebase, one set of dependencies and one upgrade path, still producing five separate apps with their own store listings and experience.
- Where did the old repositories go?
- They keep shipping until their app moves to Omni, then they are archived. Critical fixes made there in the meantime are mirrored here.
Distributed under the Apache License 2.0. See LICENSE for more information.