GioJSdocs
On this page

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     # /settings

Reference

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.tsx answers /pricing; /marketing/pricing is a 404.
  • Scoped files. A layout.tsx, loading.tsx, error.tsx or not-found.tsx in the group applies to the routes inside it and to no others, exactly as in any folder.
  • Everything routes through it. Pages, route.ts files (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 file

The 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 # /login

Good to know

  • Unlike Next.js, a group cannot hold a second root layout. Only app/layout.tsx renders the document; a group's layout.tsx is 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's not-found.tsx is for notFound() 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 (.)photo or @modal are 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.css is /(site)/site.css). Import it instead (see CSS files).

Version history

VersionChanges
v0.1.0-beta.8Introduced: (group) folders no longer appear in URLs, and their layouts and segment files apply only inside them. Overlapping routes stop startup.