IO App: an Nx monorepo behind the Italian public services app
IO, l'app dei servizi pubblici
At a glance
- What is it?
- The io-app repository holds the source of the IO mobile app, the official app for Italian public services, together with the shared packages that power it. It is a React Native and TypeScript workspace built on Nx and pnpm, with code generated from OpenAPI specs.
- Who is it for?
- io-app is a reference for teams building a large mobile product in an Nx and pnpm workspace with generated API types, a shared design system and strict rules about editing generated code. It is a poor template for a small team, since the bootstrap needs Node, pnpm, Ruby with bundler, Xcode for iOS and Android Studio, and the app itself is a citizen facing government product rather than a reusable library.
- Can I use it commercially?
- Yes, with conditions. EUPL-1.2 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One app, one workspace, one design system
The io-app repository hosts the source code of the IO mobile app and the shared packages that power it. IO is the official app that lets Italian citizens interact with public administration services, covering messages, payments and documents in one place, and it is developed and maintained by PagoPA S.p.A. The app itself lives under `apps/main-app` and is a React Native project, while the root of the repository is an Nx monorepo grouping the app with its companion libraries. The tree in the README lists `apps/main-app` for the app, `libs/design-system` for the component library, `.github/` for CI workflows and automation, `docs/` for architecture notes, `patches/` for pnpm package patches, `scripts/` for shared tooling, plus `nx.json` and `pnpm-workspace.yaml` at the root. Each project carries its own README with project specific instructions, so the monorepo is expected to be navigated project by project. The `patches/` directory is a pnpm convention for patching third-party packages in place, and `libs/design-system` is published to the workspace under the scoped name `@pagopa/io-app-design-system`, which the architecture table lists as the UI component layer.
The toolchain you need before you touch the code
The prerequisites table is where the real cost of this workspace shows. Node.js has a version pinned in `.node-version` and the README suggests nodenv or nvm to manage it. pnpm is managed through Corepack with its version pinned in `package.json`. Ruby has a version pinned in `apps/main-app/.ruby-version` and rbenv is suggested, which tells you the app still carries a Ruby layer, most likely for CocoaPods and the iOS pod tooling. Xcode is required for iOS builds and is macOS only, and Android Studio is required for Android builds. On top of that the README asks you to follow the React Native environment setup guide for your operating system before proceeding. The root package.json pins the package manager to pnpm with a full integrity hash and records the workspace as private, so the app is not published as a package; the design system is prepared locally with a postinstall step.
Four steps to a working checkout
The getting started section is explicit about the order of operations, and the sequence matters because the bootstrap depends on the earlier steps having installed the tools. The README gives it as one block:
# 1. Clone the repository
git clone https://github.com/pagopa/io-app.git
cd io-app
# 2. Enable Corepack and activate pnpm
corepack enable
corepack prepare --activate
# 3. Install Ruby gems (from apps/main-app)
cd apps/main-app
gem install bundler
bundle install
cd ../..
# 4. Full project bootstrap (installs JS deps, pods, and generates code)
pnpm nx run main-app:syncThe note attached to the last command explains what it does: `main-app:sync` runs `pnpm install`, gem setup, iOS pod install, and code generation from OpenAPI specs and localisation files. The instruction that follows is the one to remember, because it is the recurring maintenance cost: re-run it after pulling changes that affect any of those layers. A single `git pull` can invalidate the pods, the generated API models or the localisation files at once.
Generated code you are not allowed to edit
The code generation story is the most transferable part of this setup for any team that maintains a public API surface in a mobile app. The README warns with a CAUTION callout that files under `apps/main-app/definitions/` must never be edited manually and must always be regenerated, and the command that does it is:
# Regenerate API models from OpenAPI specs and locale files
pnpm nx run main-app:generateThat means the TypeScript models for the backend API and the localisation strings are build outputs, not source. The consequence for a contributor is that a change to the API contract is made in the spec, not in the model file, and a change to a translation is made in the source file, not in the generated output. The same generated layer is produced by the bootstrap step, so a fresh clone gets a consistent set on the first run. Environment selection works the same way, by copying one of the prepared env files:
# Target the production backend
cp apps/main-app/.env.production apps/main-app/.env
# Or target the local dev API server (io-dev-api-server)
cp apps/main-app/.env.local apps/main-app/.envNx targets instead of scripts, and the affected-file check
Every command in the README is an Nx target rather than a raw script invocation, which is what lets the workspace run only what changed. The daily commands cover running the app and checking the code. The quality gate block is:
# Type-check the whole workspace (no emit)
pnpm nx tsc-noemit main-app
pnpm nx tsc-noemit io-app-design-system
# Lint
pnpm nx lint main-app
pnpm nx lint io-app-design-system
# Run tests
pnpm nx run main-app:test-dev
# Run only affected projects
pnpm nx affected --target=lint,tsc-noemit
# Format code
pnpm formatThe `affected` target is the one that scales, since it restricts the lint and type check to projects touched by the current change. The root package.json mirrors this for CI, with a `validate` script that runs `nx affected` over lint, oxlint, test and tsc-noemit with the ci configuration and a bail flag, and a `validate-all` script using `nx run-many` for a full sweep. Formatting is wired to Nx as `nx format:write`, and there is a separate `knip` script for unused code analysis, plus a lefthook configuration for pre-commit hooks.
A state stack of Redux, Saga and XState
The architecture table in the README is short and worth reading closely, because it names an unusual combination. The mobile app framework is React Native with Expo modules, the language is TypeScript, and state management is Redux with Redux-Saga plus XState v5. That is a deliberate layering rather than a duplicate choice. Redux and Saga cover application level state and the side effects that drive it, while XState v5 covers the stateful flows where the legal transitions matter, such as an authentication or payment wizard where a screen sequence has to be enforced. The UI layer is the local `@io-app/design-system` package, and the monorepo tooling is Nx with pnpm workspaces. The `docs/` directory holds architecture notes and further documentation, and the app README is where a deeper dive into the app architecture and feature structure is documented. For an outside reader this table is the fastest way to understand how a mature React Native product in this space is put together.
What this repository is not, and what it costs to copy
Two limits are worth stating plainly. First, this is an application repository, not a library, so the reusable idea in it is the workspace structure and the generation discipline, not any component. The design system is scoped to the IO app, the app depends on a live government backend, and the whole thing is written in Italian for Italian public services. The `io-dev-api-server` referenced in the env file note is the local development API the app can point at, which is the shape of the integration. Second, the cost of a working checkout is high by the standards of a typical mobile project: a pinned Node, pnpm through Corepack, Ruby with bundler, Xcode and the pods, and Android Studio. A team without a mixed iOS and Android toolchain will not get past the bootstrap, and the nightly build badge in the README shows the project itself relies on a continuous build to keep that path working.
Editorial conclusion
io-app is a reference for teams building a large mobile product in an Nx and pnpm workspace with generated API types, a shared design system and strict rules about editing generated code. It is a poor template for a small team, since the bootstrap needs Node, pnpm, Ruby with bundler, Xcode for iOS and Android Studio, and the app itself is a citizen facing government product rather than a reusable library. Before you copy any of its structure, read the architecture notes in `docs/`, check the pinned tool versions in `.node-version` and `package.json`, and respect the rule that files under `apps/main-app/definitions/` are never edited by hand. The last push was on 2026-10-20, the project is licensed under EUPL-1.2, and the repository publishes release candidates such as 3.42.0-rc.3.
Frequently asked questions
How do I set up the io-app monorepo locally?
Clone the repository, enable Corepack and activate pnpm, install the Ruby gems with bundler from `apps/main-app`, and then run `pnpm nx run main-app:sync` to install JS dependencies, pods and generate code. The README asks you to re-run that sync command after pulling changes that affect any of those layers.
What tools does the IO App repository require?
Node.js with a version pinned in `.node-version`, pnpm managed through Corepack, Ruby with a version pinned in `apps/main-app/.ruby-version`, Xcode for iOS builds on macOS, and Android Studio for Android builds.
Can I edit the generated API models in the IO App repository directly?
No. The README marks it as a caution that files under `apps/main-app/definitions/` must never be edited manually, and that the correct approach is to regenerate them with `pnpm nx run main-app:generate`, which rebuilds the API models from OpenAPI specs and locale files.
Which state management libraries does the IO App use?
The architecture table in the README lists Redux with Redux-Saga and XState v5 for state management, on top of React Native with Expo modules, with TypeScript as the language and the local `@io-app/design-system` package for UI components.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/pagopa-io-app)Was this useful?