Skip to content

Next.js — Proxy Mode

The REP gateway runs in proxy mode in front of a Next.js server. It intercepts every HTML response and injects the __rep__ payload — no changes to the Next.js build pipeline required.

Source code at examples/nextjs-proxy/.

Client → REP Gateway :8080 (proxy mode)
↓ injects __rep__ payload into HTML responses
Next.js Server :3000

The Next.js server is never exposed directly. All traffic flows through the gateway. Config lives entirely in the gateway’s environment variables — the Next.js image is the same across every deployment.

  • Next.js App Router or Pages Router with server-side rendering (SSR)
  • You want the full Next.js server (streaming, server actions, API routes)
  • Docker Compose, Kubernetes single-container pod, or multi-service deployments
  • Directoryexamples/nextjs-proxy/
    • Directorysrc/
      • Directoryapp/
        • layout.tsx Includes RepScript for dev-time injection
        • page.tsx Server component shell
        • Directoryapi/rep/session-key/
          • route.ts Dev-only session key endpoint
      • Directorycomponents/
        • EnvDisplay.tsx Client component — reads REP vars
        • IntegrityBanner.tsx Verifies payload was not modified in transit
    • Dockerfile Next.js-only image (for docker-compose)
    • Dockerfile.single Gateway + Next.js in one image (for Kubernetes)
    • docker-compose.yml Two-service stack (recommended)
    • docker-entrypoint.sh Startup script for Dockerfile.single
    • next.config.ts
    • .rep.yaml
    • .env.example

REP runs entirely in the browser. In the App Router, use 'use client' components:

'use client';
import { useRep, useRepSecure } from '@rep-protocol/react';
export function EnvDisplay() {
// Synchronous — available on first render, no loading state
const apiUrl = useRep('API_URL', 'http://localhost:3001');
const envName = useRep('ENV_NAME', 'development');
const features = useRep('FEATURE_FLAGS', '');
// Async — decrypted via the session-key endpoint
const { value: analyticsKey, loading } = useRepSecure('ANALYTICS_KEY');
return (
<div>
<p>Environment: {envName}</p>
<p>API: {apiUrl}</p>
<p>Key: {loading ? 'loading…' : analyticsKey}</p>
</div>
);
}

The example includes an IntegrityBanner client component that verifies the payload was not modified after the gateway injected it. The SDK checks a SHA-256 SRI hash embedded on the <script id="__rep__"> tag using the Web Crypto API. A mismatch means something (a CDN, a misconfigured proxy) altered the payload in transit.

'use client';
import { useEffect, useState } from 'react';
import { rep } from '@rep-protocol/sdk';
export function IntegrityBanner() {
const [ok, setOk] = useState<boolean | null>(null);
useEffect(() => {
// _verifySRI fires as a microtask during SDK init — await a tick first
Promise.resolve().then(() => setOk(rep.verify()));
}, []);
if (ok === null) return <p>Verifying payload integrity…</p>;
if (ok) return <p>✅ Payload integrity verified</p>;
return <p>🚨 Integrity check FAILED — payload may have been tampered with</p>;
}

Recommended for development and multi-service production setups. Gateway and Next.js run as separate containers:

services:
gateway:
image: ghcr.io/ruachtech/rep/gateway:0.1.3
ports:
- "8080:8080"
environment:
REP_GATEWAY_MODE: proxy
REP_GATEWAY_UPSTREAM: "app:3000"
REP_PUBLIC_API_URL: "https://api.example.com"
REP_PUBLIC_ENV_NAME: "production"
REP_PUBLIC_FEATURE_FLAGS: "dark-mode"
REP_SENSITIVE_ANALYTICS_KEY: "ak_live_abc123"
depends_on:
- app
app:
build: .
expose:
- "3000"
environment:
NODE_ENV: production
# No REP_PUBLIC_* vars here — gateway injects them at request time
Terminal window
cd examples/nextjs-proxy
docker compose up

To change config without rebuilding:

Terminal window
# Edit REP_PUBLIC_* in docker-compose.yml, then:
docker compose up -d gateway # restart only the gateway

The project includes RepScript in app/layout.tsx and a session-key route handler. No gateway needed for development:

Terminal window
cp .env.example .env.local # if you haven't already
npm run dev

Open http://localhost:3000. RepScript injects the REP payload during next dev and returns null in production.

If you need full gateway fidelity:

Terminal window
# Terminal 1 — run Next.js dev server
npm run dev # starts on :3000
# Terminal 2 — run REP gateway in proxy mode
npx @rep-protocol/cli dev --proxy http://localhost:3000 --env .env.local

Open http://localhost:8080.