File Conventions
The file and folder names GioJS gives a meaning to: route files in app/, special folders, metadata files, and the files in the project root.
my-app/
app/
layout.tsx the document and the layout of every page
page.tsx /
not-found.tsx 404 page (also for unmatched URLs)
error.tsx 500 page and error boundary
globals.css imported by layout.tsx
sitemap.ts /sitemap.xml
(site)/ route group: no URL segment
layout.tsx
blog/
page.tsx /blog
loading.tsx Suspense fallback for /blog/...
[slug]/page.tsx /blog/:slug
_components/ private folder: never routed
api/posts/route.ts GET/POST /api/posts
public/ static files at the site root
middleware.ts redirects, rewrites, headers, guards
gio.config.ts Node plugins
gio.toml server settings
.env.local environment variables
.gio/ generated: builds, caches, route typesRoute files
These names have a meaning in app/ and every folder below it, except private folders. Component files may be .tsx, .jsx or .js (in that order of precedence); route may be .ts or .js.
| File | Purpose |
|---|---|
page.tsx | Makes a folder a route: the UI for its URL |
layout.tsx | Wraps the pages in its folder and below; the root one renders the document |
route.ts | HTTP handlers (GET, POST, PUT, PATCH, DELETE), Server-Sent Events and a WebSocket handler |
loading.tsx | Suspense fallback for its folder and below, streamed first while the content suspends |
error.tsx | The 500 page when a render fails on the server, and a client error boundary once hydrated |
not-found.tsx | The 404 page for notFound() at or below its folder; the one in app/ also answers unmatched URLs and is exported to 404.html |
Pages and layouts may also export metadata or generateMetadata for their <head> tags, and pages a few more values: see Page Exports.
error.tsx, not-found.tsx and loading.tsx may sit in any folder, including route groups and dynamic folders, and the nearest one at or above a page wins. Inside a folder they nest like this:
<Layout> layout.tsx
<ErrorBoundary> error.tsx - catches everything below, not the layout above it
<Suspense> loading.tsx - fallback while anything below suspends
...the next folder's layout, or the pageSo an error.tsx never handles errors from the layout in its own folder - the error.tsx of a parent folder does. See Error Handling and Layouts & Pages.
Folder conventions
| Folder | Effect |
|---|---|
[id] | Dynamic segment - matches exactly one URL segment (/posts/:id) |
[...slug] | Catch-all - one or more segments; params.slug is 'a/b' |
[[...slug]] | Optional catch-all - zero or more segments, so it also matches the parent URL (params.slug is '') |
(group) | Route group - organizes files and scopes a layout without adding a URL segment |
_folder | Private - never routable; for colocated components and helpers |
Layouts apply by folder ancestry: a page gets the layout.tsx of every folder from app/ down to its own, groups and dynamic folders included. When several routes match a URL the most specific wins (see matching order), and two files that answer the same URLs stop startup with an error naming both.
Param names may not start with . or contain ?, : or *; a folder like [...slug?] or [id?] fails startup instead of quietly changing what the route matches.
Metadata files
Only at the root of app/, as .ts or .js. The default export is the data, or a function returning it; export const revalidate sets how long the output is cached (default 3600 seconds).
| File | Serves |
|---|---|
sitemap.ts | /sitemap.xml from [{ url, lastModified, changeFrequency, priority, alternates }] |
robots.ts | /robots.txt from { rules, sitemap, host } |
manifest.ts | /manifest.webmanifest from a Web App Manifest object |
A public/ file with the same name wins (the server warns at startup); a page or route.ts at the same URL fails startup.
Styles
| File | Purpose |
|---|---|
Imported .css | Bundled per route, content-hashed, linked in <head> |
*.module.css | Local class names, imported as a map |
app/**/*.css | Also served at their path inside app/ (legacy) |
Project root files
| File or folder | Purpose |
|---|---|
public/ | Static files, served at the site root and under /public/ |
middleware.ts | Redirects, rewrites, headers and guards, enforced by the Rust server |
gio.config.ts | Node plugins |
gio.toml | Every server setting |
.env, .env.local, ... | Environment variables loaded at startup |
.gio/ | Generated: client bundles, stylesheets, caches, route types |
Not supported
GioJS follows the App Router's names where it has the feature. These Next.js conventions have no GioJS equivalent; a file or folder with one of these names is an ordinary module or an ordinary URL segment:
| Next.js | In GioJS |
|---|---|
global-error.tsx | Not supported. app/error.tsx covers every page; an error in the root layout itself gets the built-in error page. |
template.tsx | Not supported. Layouts keep their state across navigations; key a subtree yourself to reset it. |
default.tsx | Not supported (it belongs to parallel routes). |
Parallel routes (@slot folders) | Not supported. @slot is a literal URL segment. |
Intercepting routes ((.)photo, (..)photo, (...)photo folders) | Not supported. Such a folder is a literal URL segment. A folder named only (.) or (..) is a route group. |
forbidden.tsx, unauthorized.tsx | Not supported. Answer 401/403 with a Response from a route.ts or a page action, or redirect with a guard. |
opengraph-image.tsx, icon.png, apple-icon.png | Not supported. Use the openGraph and icons metadata fields with files from public/. |
instrumentation.ts | Not supported. Use a plugin's onStartup in gio.config.ts. |
A src/ folder | Not supported. app/ sits in the project root. GIO_APP_DIR can point at another folder, but public/, gio.toml and the other root files then belong next to that folder. |
Route segment config (dynamic, runtime, ...) | Different: see Page Exports. |