Route Groups
A folder named (name) organizes routes and scopes a layout to them without adding a segment to their URLs.
text
app/
layout.tsx # the document, for every page
(marketing)/
layout.tsx # wraps /, /pricing
page.tsx # /
pricing/page.tsx # /pricing
(app)/
layout.tsx # wraps /dashboard, /settings
error.tsx # 500 page and error boundary for them only
dashboard/page.tsx # /dashboard
settings/page.tsx # /settingsReference
Convention
A folder whose whole name is wrapped in parentheses, with at least one character and no other parentheses inside: (marketing), (site), (auth-pages). It can sit at any depth, and groups can be nested.
Behavior
- No URL segment.
app/(marketing)/pricing/page.tsxanswers/pricing;/marketing/pricingis a 404. - Scoped files. A
layout.tsx,loading.tsx,error.tsxornot-found.tsxin the group applies to the routes inside it and to no others, exactly as in any folder. - Everything routes through it. Pages,
route.tsfiles (WebSocket handlers included) and dynamic folders work inside groups. - Conflicts. Two groups that both answer a URL stop startup:
text
route conflict: app/(a)/about/page.tsx and app/(b)/about/page.tsx both resolve to "/about" - every URL must be served by exactly one fileThe same holds for a page in one group and a route.ts for the same URL in another.
Examples
An interactive site layout
The root layout never hydrates, so navigation that should prefetch, soft-navigate or keep state lives in a group's layout. This is how the create-giojs starter is built:
app/(site)/layout.tsx
import React from 'react';
import type { LayoutProps } from '@gio.js/core';
import { Navbar } from '../../components/Navbar';
import { Footer } from '../../components/Footer';
export default function SiteLayout({ children }: LayoutProps) {
return (
<>
<Navbar />
<main>{children}</main>
<Footer />
</>
);
}Pages without the site chrome
text
app/
layout.tsx # <html><body> only
(site)/layout.tsx # navbar + footer
(site)/page.tsx # /
(site)/blog/... # /blog/...
(auth)/layout.tsx # a centered card, no navbar
(auth)/login/page.tsx # /loginGood to know
- Unlike Next.js, a group cannot hold a second root layout. Only
app/layout.tsxrenders the document; a group'slayout.tsxis always a nested layout rendered inside it, so it must not render<html>or<body>. - A URL that no route answers gets
app/not-found.tsx, never a group's: an unmatched URL belongs to no folder. A group'snot-found.tsxis fornotFound()calls from its own pages. - Moving routes into or out of a group does not change their URLs, so links to them keep working.
- Folder names such as
(.)photoor@modalare not special: GioJS has no intercepting or parallel routes, and those folders are ordinary URL segments. - A stylesheet inside a group that is served by path keeps the group in its URL (
app/(site)/site.cssis/(site)/site.css). Import it instead (see CSS files).
Related
Version history
| Version | Changes |
|---|---|
v0.1.0-beta.8 | Introduced: (group) folders no longer appear in URLs, and their layouts and segment files apply only inside them. Overlapping routes stop startup. |