Skip to main content
Both apps in the monorepo share a consistent configuration philosophy: keep the Next.js config minimal, rely on static export, and bake all SEO signals into the exported HTML at build time. This page walks through every configuration file that matters for how the apps are built, deployed, and discovered.

next.config.js

The single most important setting in each app is output: 'export'. This instructs Next.js to emit a fully static site into an out/ directory instead of starting a Node.js server. Vercel serves that directory directly from its CDN edge nodes. Both apps also set images.unoptimized: true because Next.js image optimization requires a server-side runtime. With static export enabled, the built-in <Image> component must skip optimization and serve the raw source files. The main site additionally enables productionBrowserSourceMaps: true so that coverage tooling can map data back to the original TypeScript source.
// @ts-check

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  output: 'export',
  // Emit browser source maps so Playwright V8 coverage maps back to source
  // (see e2e/fixtures.ts). Only consumed by the coverage tooling; harmless in prod.
  productionBrowserSourceMaps: true,
  images: {
    unoptimized: true,
  },
}

module.exports = nextConfig
reactStrictMode: true enables React’s strict mode in development, which surfaces potential issues by double-invoking certain lifecycle methods. It has no effect on the production build output.

vercel.json

Both apps carry a vercel.json that controls which branches receive Vercel preview deployments. All other Vercel settings — root directory, build command, output directory — are configured in the Vercel dashboard per project, keeping this file lean.
{
  "git": {
    "deploymentEnabled": {
      "pr-screenshots": false
    }
  }
}

tsconfig.json

Both apps use a standard Next.js TypeScript configuration. The key setting for day-to-day development is the paths alias, which maps @/* to the project root. This lets you import any file from the project using a clean absolute-style path instead of navigating relative directories.
main/tsconfig.json
{
  "compilerOptions": {
    "target": "es2022",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "react-jsx",
    "incremental": true,
    "paths": {
      "@/*": ["./*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules", "playwright.config.ts", "e2e"]
}
Use the @/ alias whenever you import styles, components, or utilities. For example, import styles from '@/styles/Home.module.css' works from any file depth without ../ chains.

robots.txt

The main site’s robots.txt allows all crawlers to index all pages and points to the sitemap location. The resume subdomain does not include a separate robots.txt — crawlers fall back to permissive defaults.
main/public/robots.txt
User-agent: *
Allow: /

Sitemap: https://war.re/sitemap.xml

sitemap.xml

Each app ships a minimal sitemap that declares a single canonical URL — the /n path where the real content lives. The root / path is intentionally excluded because it only contains the meta-refresh redirect; /n is the indexable destination.
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://war.re/n</loc>
    <changefreq>monthly</changefreq>
    <priority>1.0</priority>
  </url>
</urlset>

SEO Metadata

Both apps embed their SEO metadata directly inside each page’s <Head> component. Because there is no server and no templating layer at runtime, all meta tags must be statically declared at build time and exported as part of the HTML. Every page includes:
  • <title> and <meta name="description"> — for search engine result snippets
  • <meta name="robots"> and <meta name="googlebot"> — set to index, follow to ensure the pages are crawled and indexed
  • <link rel="canonical"> — points to the /n path on the appropriate domain, preventing duplicate-content issues caused by the / redirect
  • Open Graph tags (og:type, og:url, og:title, og:description, og:image) — for rich link previews on social platforms; the OG image is served from /og.svg at 1200×630
  • Twitter Card tags (twitter:card, twitter:title, twitter:description) — for Twitter/X link unfurls
  • <meta name="author"> (resume page) — identifies the page author explicitly
The root pages/index.tsx in each app also includes the <meta http-equiv="refresh" content="0; url=/n"> tag that performs the client-side redirect. A <noscript> fallback link is included for browsers that have JavaScript and meta-refresh disabled.
Open Graph images are static SVG files committed to each app’s public/ directory. Because images.unoptimized: true is set in next.config.js, you can reference them with a plain <meta> tag and they will be served as-is with no server-side processing.