Docs
Next

Gateway and status codes

Configure systhemaGateway for Admin routing, frontend locales and correct not-found responses.

On this page

systhemaGateway(options) returns the request handler exported as proxy from src/proxy.ts. Import it from @systhemaui/next/gateway; Payload sites can import the same function from @systhemaui/payload/gateway.

systhemaGatewayLink to this section

src/proxy.ts
import { systhemaGateway } from '@systhemaui/next/gateway'

export const proxy = systhemaGateway({ adminRouting: false })

Use adminRouting: false for Next-only applications. Payload sites normally keep Admin routing enabled:

src/proxy.ts
import { systhemaGateway } from '@systhemaui/payload/gateway'

export const proxy = systhemaGateway({
  customAdminURL: process.env.ADMIN_URL,
})
OptionDefaultBehavior
adminRouting?: booleantrueReserves the Admin path and enables custom Admin-host routing.
customAdminURL?: stringUnsetAbsolute HTTP(S) Admin URL; its hostname identifies the Admin host.
customAdminPath?: string/adminAbsolute pathname for the internal Admin route. Trailing slashes are removed; query strings, fragments and ./.. segments are rejected. / is allowed.
trustForwardedHost?: booleanfalseUses the first x-forwarded-host value for Admin-host detection. Enable only behind a proxy that overwrites that header.
`locales?: SysthemaLocalesfalse`Injected contract
localeMiddleware?: (request: NextRequest) => Response | undefinedBuilt-in locale proxyAdvanced override for the locale handler.

Invalid Admin URL or path options throw when constructing the gateway. Host detection uses the trusted forwarded host when enabled, then Host, then the request URL hostname. It compares hostnames, not URL paths or ports.

Request flowLink to this section

The gateway runs these steps in order:

  1. Detect the configured Admin host, the Admin path, Preview and Live Preview. Preview is __livePreview=true or the presence of __previewCollection.
  2. Rewrite anonymous Admin file probes to /not-found before excluding asset paths.
  3. Pass through infrastructure paths: /sys, /api, /trpc, /_next, /_vercel, /favicon.ico, /robots.txt, and paths with a dot in any segment. Prefix matching respects segment boundaries, so /apiary is not /api.
  4. Pass Admin paths through on the Admin host, or when no custom host is configured. On a different host, rewrite them to /not-found.
  5. On a custom Admin host, rewrite non-Preview page requests under the internal Admin path. For example, /collections/pages becomes /admin/collections/pages.
  6. Run feature handlers, currently frontend locales, and return the first response. Without a handler response, continue to Next.js.
  7. Remove entity-tag request revalidation from eligible forwarded page requests.

The gateway reserves no special Admin prefix when customAdminPath is /. Preview and Live Preview on the custom Admin host fall through to locale handling rather than the Admin rewrite. Domain-routed previews render on the origin they arrived on; moving the iframe across hosts would break its session and live messages. An unsupported explicit __systhemaPreviewLocale returns 400.

See Routing helpers for locale proxy behavior and Frontend locales for configuration.

Status codesLink to this section

The gateway strips If-None-Match from forwarded page requests, including rewrites. Next otherwise turns a matching entity tag into 304 even for a cached 404. Removing that request header lets the origin return the actual status and body. It preserves other request headers, including locale middleware overrides, and does not strip the response's ETag.

Requests under /sys, /api, /trpc, /_next and /_vercel retain If-None-Match. Responses that neither continue nor rewrite, such as redirects, retain it too. Other asset paths bypass locale routing but are still subject to the forwarding-header rule. If-Modified-Since remains available for static-file revalidation.

Anonymous Admin paths with a dot in a segment, such as /admin/.env or /admin/wp-login.php, rewrite to the site's not-found route. The gateway considers any cookie whose name ends in -token a session indicator; it does not authenticate that cookie itself. Requests with that indicator reach Payload.

This guard avoids Payload's anonymous 200 Admin shell for obvious file probes. Unknown Admin paths without a dot, such as /admin/foo, can still return 200 anonymously. Payload's AuthProvider renders nothing during server rendering before resolving the user, so an Admin notFound() or redirect() does not establish the response status. The gateway does not look up every CMS page or authenticate every request; your page routes still need to return their own not-found responses.