CLI commands
rndl routes
Print the deep-linkable route table of an Expo Router or React Navigation app, as an aligned table or JSON.
rndl routes scans your app and prints every deep-linkable route with its URL pattern and params.
It is the foundation the other commands build on: validate cross-checks this table against your
AASA file, open and interactive build URLs from it, and typegen turns it into types.
rndl routes # auto-detects app/ then src/app/
rndl routes --json # routes, API routes, layouts, diagnostics
rndl routes --app-dir src/app # explicit Expo Router directory
rndl routes --config src/navigation/linking.ts # default or `linking` export
rndl routes --config src/navigation/linking.ts#named # a specific named exportFlags
| Flag | Description |
|---|---|
--json | Print the full scan result as JSON instead of the aligned table. |
--app-dir <dir> | Expo Router app directory. Defaults to app/, then src/app/. |
--config <module[#export]> | React Navigation linking module, with an optional named export after #. |
--app-dir and --config are mutually exclusive: an app has one router.
Expo Router
The adapter walks your app directory and understands every file convention:
- Dynamic segments (
[id]) and catch-alls ([...slug]). - Route groups (
(group)), including the array syntax ((a,b)) that expands one file into a route per group. - Platform-specific variants (
.ios,.android,.native,.web). _layoutfiles (structural, not routes),indexfiles (the parent path), and+not-found.- The special files
+api(excluded and tagged as an API route),+html,+native-intent, and+middleware.
Conventions it does not recognize produce a warning, never a crash, so a new router release does not break your CI run.
React Navigation
The adapter imports your linking module under Node (TypeScript and ESM are handled for you) and
walks config.screens recursively, honoring nested navigators, path, exact, alias,
regex-constrained and optional params, wildcards, and prefixes. Params with a custom parse
function are reported as unknown (custom parse), since their runtime type is not knowable from
the config.
Because the module is executed outside the native runtime, keep the linking config in an isolated
module that only exports plain data and parse/stringify functions (react-navigation imports
are fine as import type):
// src/navigation/linking.ts
import type { LinkingOptions } from '@react-navigation/native';
export const linking = {
prefixes: ['myapp://', 'https://example.com'],
config: {
screens: {
Home: '',
Article: { path: 'article/:slug', exact: true },
},
},
} satisfies LinkingOptions<Record<string, unknown>>;If the import fails because the module pulls in native code, rndl prints an actionable error
suggesting this isolated-module pattern.