0
# Route Management
1
2
Advanced routing system supporting flat routes, custom route definitions, nested routes, and dynamic route generation with TypeScript support.
3
4
## Capabilities
5
6
### Route Definition
7
8
Programmatic route definition for creating custom routing structures beyond filesystem conventions.
9
10
```typescript { .api }
11
/**
12
* Define custom routes programmatically (unstable API)
13
* @param callback - Function that receives defineRoutes helper
14
* @returns Route manifest with defined routes
15
*/
16
function UNSAFE_defineRoutes(
17
callback: (defineRoutes: DefineRouteFunction) => void
18
): RouteManifest;
19
20
/**
21
* Function for defining individual routes
22
*/
23
interface DefineRouteFunction {
24
(
25
/** Route path or undefined for pathless layout routes */
26
path: string | undefined,
27
/** File path relative to app directory */
28
file: string,
29
/** Route options or children callback */
30
optionsOrChildren?: DefineRouteOptions | (() => void),
31
/** Children callback for nested routes */
32
children?: () => void
33
): void;
34
}
35
36
interface DefineRouteOptions {
37
/** Whether this is an index route */
38
index?: boolean;
39
/** Whether route matching is case sensitive */
40
caseSensitive?: boolean;
41
/** Unique route identifier */
42
id?: string;
43
}
44
45
type DefineRoutesFunction = typeof UNSAFE_defineRoutes;
46
```
47
48
### Flat Routes
49
50
Flat route system that creates route hierarchy from filesystem structure using naming conventions.
51
52
```typescript { .api }
53
/**
54
* Create flat routes from app directory structure (unstable API)
55
* @param appDirectory - Path to app directory
56
* @param ignoredFilePatterns - Patterns for files to ignore
57
* @param prefix - Route prefix
58
* @returns Route manifest generated from flat routes
59
*/
60
function UNSAFE_flatRoutes(
61
appDirectory: string,
62
ignoredFilePatterns?: string[],
63
prefix?: string
64
): RouteManifest;
65
66
/**
67
* Universal flat routes implementation
68
* @param appDirectory - App directory path
69
* @param routes - Explicit route definitions
70
* @param prefix - Route prefix
71
* @param visitFiles - Function to visit files
72
* @returns Route manifest
73
*/
74
function flatRoutesUniversal(
75
appDirectory: string,
76
routes: string[],
77
prefix?: string,
78
visitFiles?: (dir: string) => string[]
79
): RouteManifest;
80
```
81
82
### Route Manifest Management
83
84
Functions for working with route manifests and converting between different route representations.
85
86
```typescript { .api }
87
/**
88
* Convert route manifest to route configuration (unstable API)
89
* @param routeManifest - Route manifest to convert
90
* @param rootDirectory - Root directory path
91
* @returns Route configuration array
92
*/
93
function UNSAFE_routeManifestToRouteConfig(
94
routeManifest: RouteManifest,
95
rootDirectory: string
96
): RouteConfig;
97
98
/**
99
* Get app directory for route configuration (unstable API)
100
* @returns Current app directory path
101
*/
102
function UNSAFE_getRouteConfigAppDirectory(): string;
103
104
/**
105
* Set app directory for route configuration (unstable API)
106
* @param directory - App directory path to set
107
*/
108
function setRouteConfigAppDirectory(directory: string): void;
109
110
/**
111
* Get current app directory for route configuration
112
* @returns App directory path
113
*/
114
function getRouteConfigAppDirectory(): string;
115
```
116
117
### Route Configuration Validation
118
119
Schema validation and configuration processing for routes.
120
121
```typescript { .api }
122
/**
123
* Validate route configuration against schema
124
* @param options - Validation options
125
* @returns Validation result with errors or success
126
*/
127
function validateRouteConfig(options: {
128
routeConfig: unknown;
129
rootDirectory: string;
130
}): { success: true; config: RouteConfig } | { success: false; errors: string[] };
131
132
/**
133
* Convert route configuration to route manifest
134
* @param routeConfig - Route configuration to convert
135
* @param rootDirectory - Root directory path
136
* @param appDirectory - App directory path
137
* @returns Route manifest
138
*/
139
function configRoutesToRouteManifest(
140
routeConfig: RouteConfig,
141
rootDirectory: string,
142
appDirectory: string
143
): RouteManifest;
144
```
145
146
### Route Types
147
148
Core types for route management and configuration.
149
150
```typescript { .api }
151
/**
152
* Route manifest containing all application routes
153
*/
154
interface RouteManifest {
155
[routeId: string]: RouteManifestEntry;
156
}
157
158
/**
159
* Individual route entry in the manifest
160
*/
161
interface RouteManifestEntry {
162
/** Unique route identifier */
163
id: string;
164
/** Parent route ID for nested routes */
165
parentId?: string;
166
/** URL path pattern */
167
path?: string;
168
/** Whether this is an index route */
169
index?: boolean;
170
/** Whether route matching is case sensitive */
171
caseSensitive?: boolean;
172
/** File path relative to app directory */
173
file: string;
174
/** Whether route has action export */
175
hasAction: boolean;
176
/** Whether route has loader export */
177
hasLoader: boolean;
178
/** Whether route has clientAction export */
179
hasClientAction: boolean;
180
/** Whether route has clientLoader export */
181
hasClientLoader: boolean;
182
/** Whether route has ErrorBoundary export */
183
hasErrorBoundary: boolean;
184
/** Import dependencies */
185
imports?: string[];
186
}
187
188
/**
189
* Route configuration entry
190
*/
191
interface RouteConfigEntry {
192
/** Route file path */
193
file: string;
194
/** Route ID */
195
id?: string;
196
/** Route path */
197
path?: string;
198
/** Whether this is an index route */
199
index?: boolean;
200
/** Whether route matching is case sensitive */
201
caseSensitive?: boolean;
202
/** Parent route ID */
203
parentId?: string;
204
}
205
206
/** Schema for validating route configuration entries */
207
const routeConfigEntrySchema: ValidationSchema<RouteConfigEntry>;
208
209
/** Schema for validating resolved route configuration */
210
const resolvedRouteConfigSchema: ValidationSchema<RouteConfig>;
211
212
/** Resolved route configuration array */
213
type ResolvedRouteConfig = RouteConfigEntry[];
214
215
/** Route configuration (resolved or promise of resolved) */
216
type RouteConfig = ResolvedRouteConfig | Promise<ResolvedRouteConfig>;
217
```
218
219
### Route Path Utilities
220
221
Utilities for working with route paths and segments.
222
223
```typescript { .api }
224
/**
225
* Get route segments from route ID
226
* @param routeId - Route ID to parse
227
* @returns Tuple of path segments and layout segments
228
*/
229
function getRouteSegments(routeId: string): [string[], string[]];
230
231
/**
232
* Create route path from segments
233
* @param routeId - Route ID
234
* @param segments - Route segments
235
* @param isIndex - Whether this is an index route
236
* @returns Generated route path
237
*/
238
function createRoutePath(
239
routeId: string,
240
segments: string[],
241
isIndex: boolean
242
): string | undefined;
243
244
/**
245
* Create route ID from file path
246
* @param file - File path to convert
247
* @returns Route ID
248
*/
249
function createRouteId(file: string): string;
250
251
/**
252
* Normalize slashes in file path
253
* @param file - File path to normalize
254
* @returns Normalized file path
255
*/
256
function normalizeSlashes(file: string): string;
257
```
258
259
### Flat Routes Constants
260
261
Constants used in flat routes naming conventions.
262
263
```typescript { .api }
264
/** Supported route module file extensions */
265
const routeModuleExts: string[];
266
267
/** Character used to prefix route parameters */
268
const paramPrefixChar: "$";
269
270
/** Character to start escaped route segments */
271
const escapeStart: "[";
272
273
/** Character to end escaped route segments */
274
const escapeEnd: "]";
275
276
/** Character to start optional route segments */
277
const optionalStart: "(";
278
279
/** Character to end optional route segments */
280
const optionalEnd: ")";
281
282
/**
283
* Check if character is a segment separator
284
* @param checkChar - Character to check
285
* @returns Whether character is a segment separator
286
*/
287
function isSegmentSeparator(checkChar: string | undefined): boolean;
288
```
289
290
### Error Messages
291
292
Functions for generating helpful error messages for route conflicts.
293
294
```typescript { .api }
295
/**
296
* Generate error message for route path conflicts
297
* @param routeId - Conflicting route ID
298
* @param routePath - Conflicting route path
299
* @param existingRouteId - Existing route ID
300
* @param existingRoutePath - Existing route path
301
* @returns Formatted error message
302
*/
303
function getRoutePathConflictErrorMessage(
304
routeId: string,
305
routePath: string,
306
existingRouteId: string,
307
existingRoutePath: string
308
): string;
309
310
/**
311
* Generate error message for route ID conflicts
312
* @param routeId - Conflicting route ID
313
* @param existingRouteId - Existing route ID
314
* @returns Formatted error message
315
*/
316
function getRouteIdConflictErrorMessage(
317
routeId: string,
318
existingRouteId: string
319
): string;
320
```
321
322
## Usage Examples
323
324
### Custom Route Definition
325
326
```typescript
327
// remix.config.js
328
import { UNSAFE_defineRoutes } from "@remix-run/dev";
329
330
export default {
331
routes(defineRoutes) {
332
return defineRoutes((route) => {
333
// Root route
334
route("/", "routes/home.tsx");
335
336
// Nested routes
337
route("/blog", "routes/blog.tsx", () => {
338
route("", "routes/blog/index.tsx", { index: true });
339
route(":slug", "routes/blog/post.tsx");
340
});
341
342
// Admin routes with layout
343
route("/admin", "routes/admin.tsx", () => {
344
route("dashboard", "routes/admin/dashboard.tsx");
345
route("users", "routes/admin/users.tsx");
346
route("users/:id", "routes/admin/user.tsx");
347
});
348
349
// Pathless layout route
350
route(undefined, "routes/auth-layout.tsx", () => {
351
route("/login", "routes/login.tsx");
352
route("/register", "routes/register.tsx");
353
});
354
});
355
},
356
};
357
```
358
359
### Flat Routes Structure
360
361
```
362
app/
363
├── routes/
364
│ ├── _index.tsx # /
365
│ ├── about.tsx # /about
366
│ ├── blog._index.tsx # /blog
367
│ ├── blog.$slug.tsx # /blog/:slug
368
│ ├── blog_.special.tsx # /blog/special (escapes parent layout)
369
│ ├── admin.tsx # /admin (layout)
370
│ ├── admin._index.tsx # /admin (index)
371
│ ├── admin.users.tsx # /admin/users
372
│ ├── admin.users.$id.tsx # /admin/users/:id
373
│ ├── admin.settings.tsx # /admin/settings
374
│ └── ($lang)._index.tsx # /:lang (optional param)
375
```
376
377
### Route Manifest Processing
378
379
```typescript
380
import {
381
UNSAFE_flatRoutes,
382
UNSAFE_routeManifestToRouteConfig,
383
validateRouteConfig
384
} from "@remix-run/dev";
385
386
// Generate routes from flat routes
387
const routeManifest = UNSAFE_flatRoutes("./app", ["**/.*"]);
388
389
// Convert to route config
390
const routeConfig = UNSAFE_routeManifestToRouteConfig(
391
routeManifest,
392
process.cwd()
393
);
394
395
// Validate configuration
396
const validation = validateRouteConfig({
397
routeConfig,
398
rootDirectory: process.cwd(),
399
});
400
401
if (validation.success) {
402
console.log("Valid route configuration:", validation.config);
403
} else {
404
console.error("Route validation errors:", validation.errors);
405
}
406
```
407
408
### Route Information Display
409
410
```typescript
411
import { formatRoutes } from "@remix-run/dev";
412
413
const routeManifest = {
414
"routes/_index": {
415
id: "routes/_index",
416
file: "routes/_index.tsx",
417
path: "/",
418
index: true,
419
},
420
"routes/blog": {
421
id: "routes/blog",
422
file: "routes/blog.tsx",
423
path: "/blog",
424
},
425
"routes/blog.$slug": {
426
id: "routes/blog.$slug",
427
parentId: "routes/blog",
428
file: "routes/blog.$slug.tsx",
429
path: ":slug",
430
},
431
};
432
433
// Format as JSX tree
434
const jsxOutput = formatRoutes(routeManifest, "jsx");
435
console.log(jsxOutput);
436
437
// Format as JSON
438
const jsonOutput = formatRoutes(routeManifest, "json");
439
console.log(jsonOutput);
440
```