Remix V2 Routing
/install remix-v2-routing
Remix v2 Routing
Quick Reference
Flat-routes v2 filename rules (all files live in app/routes/):
_index.tsx → /
concerts.tsx → /concerts (acts as layout when dotted children exist; otherwise leaf for /concerts)
concerts._index.tsx → /concerts (renders under layout)
concerts.$city.tsx → /concerts/:city params.city
concerts.trending.tsx → /concerts/trending
_auth.tsx + _auth.login.tsx → /login (pathless layout, no URL segment)
files.$.tsx → /files/* params["*"]
($lang)._index.tsx → / and /en (or /fr etc.) — optional segment
sitemap[.]xml.tsx → /sitemap.xml (escape literal)
concerts_.mine.tsx → /concerts/mine (opts out of layout)
dashboard/route.tsx → /dashboard (folder + route.tsx)
reports.$id[.pdf].tsx → /reports/:id.pdf (no default export = resource)
Imports — always use @remix-run/react, never react-router-dom:
import { Outlet, Link, useLoaderData, useParams } from "@remix-run/react";
import type { LoaderFunctionArgs } from "@remix-run/node"; // or /cloudflare, /deno
File Naming Conventions
Dots in filenames create URL slashes and parent/child nesting. Underscore prefix marks pathless segments (_auth.tsx) and index routes (_index.tsx). Trailing underscore (concerts_.mine.tsx) opts out of layout nesting while keeping the URL nested. Brackets escape literal characters: sitemap[.]xml.tsx. Splat is the single dollar sign: $.tsx exposes the rest of the path under params["*"]. Optional segments are wrapped in parens: ($lang).
See references/conventions.md for the full table and edge cases.
Nested Layouts
A parent module (concerts.tsx) renders \x3COutlet />; child routes (concerts.$city.tsx, concerts._index.tsx) mount inside it automatically based on the dot-delimited filename.
// app/routes/concerts.tsx
import { Outlet } from "@remix-run/react";
export default function ConcertsLayout() {
return (
\x3Csection>
\x3Cnav>{/* concerts subnav */}\x3C/nav>
\x3COutlet />
\x3C/section>
);
}
// app/routes/concerts._index.tsx (renders at exactly /concerts)
export default function ConcertsIndex() {
return \x3Ch1>Browse concerts\x3C/h1>;
}
For a layout with no URL contribution, prefix with a single underscore:
// app/routes/_auth.tsx → wraps /login, /signup; no URL segment
// app/routes/_auth.login.tsx → /login (inherits _auth layout)
// app/routes/_auth.signup.tsx → /signup
Dynamic Segments and Splats
$name captures a single segment; $.tsx captures the rest of the path. Loader receives values via params:
// app/routes/concerts.$city.tsx
import type { LoaderFunctionArgs } from "@remix-run/node";
import { json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
export async function loader({ params }: LoaderFunctionArgs) {
if (!params.city) throw new Response("Not found", { status: 404 });
return json({ city: params.city });
}
export default function City() {
const { city } = useLoaderData\x3Ctypeof loader>();
return \x3Ch1>{city}\x3C/h1>;
}
Splat values live under "*" — there is no params.splat:
// app/routes/files.$.tsx
export async function loader({ params }: LoaderFunctionArgs) {
const rest = params["*"]; // bracket access only
return new Response(await readBlob(rest), { headers: { "Content-Type": "application/octet-stream" } });
}
Root Module
app/root.tsx is the only required route. It owns the document shell and must render \x3CMeta />, \x3CLinks />, \x3COutlet />, \x3CScrollRestoration />, \x3CScripts />, and (during dev) \x3CLiveReload />. See references/root.md.
Resource Routes
A route module without a default export is a resource route — it returns raw Response objects (PDF, JSON, RSS, webhooks). Parent loaders do not run, and \x3CLink> must use reloadDocument (or be replaced with \x3Ca>) to trigger a real document request. See references/resource-routes.md.
Gates (decision sequencing)
Answer in order. Pass means the condition is true; pick the answer on the same line and stop.
Layout vs flat URL
- Is there shared chrome at all (nav, breadcrumbs, sidebar) at this level?
- Fail → Use plain dotted segments (
about.tsx,pricing.tsx); no layout module needed. Stop. - Pass → Step 1.
- Fail → Use plain dotted segments (
- Should this URL share UI (nav, breadcrumbs, sidebar) with a parent path?
- Pass → Use dot-delimited nesting (
concerts.$city.tsxunderconcerts.tsx). Stop. - Fail → Step 2.
- Pass → Use dot-delimited nesting (
- Does the URL just happen to be nested but should render standalone?
- Pass → Trailing underscore (
concerts_.mine.tsx). Stop. - Fail → Step 3.
- Pass → Trailing underscore (
- Need a wrapper layout but no parent URL segment?
- Pass → Single-underscore pathless parent (
_auth.tsx+_auth.login.tsx). Stop.
- Pass → Single-underscore pathless parent (
UI route vs resource route
- Does this URL ever render HTML to a user?
- Pass → Export a
defaultcomponent. UI route. Stop. - Fail → Step 2.
- Pass → Export a
- Returns JSON, PDF, RSS, sitemap, webhook, or other raw
Response?- Pass → Omit
defaultexport — module becomes a resource route. UsereloadDocumenton any\x3CLink>pointing to it. Stop.
- Pass → Omit
_index.tsx vs index.tsx
- On Remix v2 with flat-routes?
- Pass →
_index.tsx(leading underscore). Stop. - Fail → Step 2 — you're on v1 (or using the v1 fallback adapter).
- Pass →
- Need to keep a v1 nested-folder tree alive?
- Pass → Install
@remix-run/v1-route-conventionand wire it inremix.config.js. See references/v1-migration.md. Stop.
- Pass → Install
Additional Documentation
- Conventions: See references/conventions.md for the full filename grammar (
_index,_layout,$param, splat, optional, escape, folder +route.tsx, trailing underscore). - Root module: See references/root.md for the
root.tsxscaffold and the required document elements. - Resource routes: See references/resource-routes.md for non-HTML responses, the no-
default-export rule, parent-loader skipping, andreloadDocument. - v1 → v2 migration: See references/v1-migration.md for differences from v1 (
__doubleunderscore folders,index.tsx,@remix-run/v1-route-convention,ignoredRouteFiles).
v1 vs v2 Convention Comparison
| Concern | v1 (nested folders) | v2 (flat routes) |
|---|---|---|
| Index route | index.tsx |
_index.tsx |
| Pathless layout | __auth/ (double underscore) |
_auth.tsx (single) |
| Nested URL | folder hierarchy | dot delimiter in filename |
| Dynamic segment | $param.tsx |
$param.tsx (unchanged) |
| Splat | $.tsx |
$.tsx (unchanged) |
| Escape literal | n/a | [.], [] brackets |
| Opt-out of layout | move out of folder | trailing _ (foo_.bar.tsx) |
| Co-location | adjacent files in folder | feature/route.tsx + siblings |
| Fallback adapter | n/a | @remix-run/v1-route-convention |
- 确保已安装 OpenClaw(本地或 Docker 部署)
- 在对话框中输入安装命令:
/install remix-v2-routing - 安装完成后,直接呼叫该 Skill 的名称或使用
/remix-v2-routing触发 - 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
Remix V2 Routing 是什么?
Remix v2 routing patterns. Use when implementing flat-routes v2 conventions, route file naming, nested layouts, resource routes, or root.tsx scaffolding. Tri... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 15 次。
如何安装 Remix V2 Routing?
在 OpenClaw 或 Claude Code 对话框中运行命令「/install remix-v2-routing」即可一键安装,无需额外配置。
Remix V2 Routing 是免费的吗?
是的,Remix V2 Routing 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。
Remix V2 Routing 支持哪些平台?
Remix V2 Routing 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。
谁开发了 Remix V2 Routing?
由 Kevin Anderson(@anderskev)开发并维护,当前版本 v1.0.0。