nx-dev/nx-dev/DEPLOYMENT.md
This document explains how nx.dev is deployed on Netlify and how requests are routed between three distinct systems: Framer (marketing pages), Next.js (blog, courses, etc.), and Astro (documentation).
Request -> Netlify Edge Functions -> _redirects -> Next.js rewrites -> Next.js App
| | |
v v v
Framer (301s) Astro
(marketing) (/docs)
Routing priority:
rewrite-framer-urls.ts) - proxies marketing pages to Framer_redirects file - 301 permanent redirectsnext.config.js) - proxies /docs/* to AstroWhen a request hits nx.dev, it goes through the following stages in order:
Edge functions run first, before any other routing. Located at /netlify/edge-functions/ in the repository root (see Why repo root?).
| Edge Function | Path Pattern | Purpose |
|---|---|---|
rewrite-framer-urls.ts | /* | Proxies marketing pages to Framer |
additional-sitemaps.ts | /sitemap-1.xml, /sitemap-2.xml | Proxies Framer's and nx-blog's sitemaps with URL rewriting |
_redirects)After edge functions, Netlify processes _redirects. This file contains 301 permanent redirects for:
Rules are processed top-to-bottom, first match wins. Specific rules must come before wildcard rules.
next.config.js)If no redirect matches, Next.js rewrites handle:
| Pattern | Destination | Description |
|---|---|---|
/docs | ${ASTRO_URL}/docs | Documentation root |
/docs/:path* | ${ASTRO_URL}/docs/:path* | All documentation pages |
/.netlify/:path* | ${ASTRO_URL}/.netlify/:path* | Netlify functions/assets |
/llms.txt | ${ASTRO_URL}/docs/llms.txt | LLM-friendly docs index |
/llms-full.txt | ${ASTRO_URL}/docs/llms-full.txt | Full LLM documentation |
Finally, if nothing else matches, the Next.js application serves the page from app/ or returns 404.
Environment Variable: NEXT_PUBLIC_FRAMER_URL
Framer hosts the marketing website, including:
/)/nx-cloud/enterprise, /enterprise/security, /enterprise/trial/community, /company, /contact/*/customers, /customer-stories/solutions/*, /partners/webinars, /careers, /brands/java, /react, /resourcesThe rewrite-framer-urls.ts edge function:
/*)excludedPath config or nextjsPaths setURL Rewriting: All Framer URLs in responses are rewritten from NEXT_PUBLIC_FRAMER_URL to https://nx.dev to ensure:
Location: nx-dev/nx-dev/
The Next.js application handles:
/blog, /blog/* - Blog posts/courses, /courses/* - Video courses/pricing - Pricing page/podcast - Podcast episodes/ai-chat - AI assistant/changelog - Changelog/resources-library - Resources/whitepaper-fast-ci - WhitepaperThese paths are defined in nextjsPaths within rewrite-framer-urls.ts and bypass the Framer proxy.
Location: astro-docs/
Environment Variable: NEXT_PUBLIC_ASTRO_URL
The Astro site handles all /docs/* paths. It's deployed as a separate Netlify site and proxied through Next.js rewrites.
Deploy Preview Behavior:
During deploy previews, the Next.js app automatically points to the matching Astro preview:
// next.config.js
if (process.env.CONTEXT === 'deploy-preview' && process.env.REVIEW_ID) {
process.env.NEXT_PUBLIC_ASTRO_URL = `https://deploy-preview-${process.env.REVIEW_ID}--nx-docs.netlify.app`;
}
Location: /netlify/edge-functions/ (repo root)
netlify/
└── edge-functions/
├── README.md
├── rewrite-framer-urls.ts # Main Framer proxy
└── additional-sitemaps.ts # Framer + nx-blog sitemap proxy
Edge functions must be at the repo root because of Netlify's configuration:
. (repository root)./nx-dev/nx-dev/.nextNetlify auto-discovers edge functions from netlify/edge-functions/ relative to the base directory. Custom paths via edge_functions in netlify.toml are not recognized.
Location: nx-dev/nx-dev/_redirects
The _redirects file contains all 301 permanent redirects. It is copied to .next/_redirects during the Netlify build.
File Structure:
# --- section-name ---
/old-path /new-path 301
/pattern/* /new-pattern/:splat 301
Sections include:
docs - Documentation entry pointcliUrls - CLI command redirectsdiataxis - Legacy structure redirectsguideUrls - Guide page redirectsrecipesUrls - Recipe page redirectsnxCloudUrls - Nx Cloud redirectstutorialRedirects - Tutorial redirectsnxApiRedirects - API reference redirectsLocation: nx-dev/nx-dev/next.config.js
Key configurations:
rewrites() - Proxies /docs/* to AstrotranspilePackages - Workspace librariesheaders() - Security headersoutputFileTracingExcludes - Reduces function bundle sizeLocation: nx-dev/nx-dev/netlify.toml
[[plugins]]
package = "@netlify/plugin-nextjs"
[functions]
included_files = [
"!node_modules/@swc/core-*/**",
# ... exclusions to stay under 250MB limit
]
| Variable | Description | Example |
|---|---|---|
NEXT_PUBLIC_FRAMER_URL | Framer site URL for marketing pages | https://ready-knowledge-238309.framer.app |
NEXT_PUBLIC_ASTRO_URL | Astro docs site URL | https://master--nx-docs.netlify.app |
NEXT_PUBLIC_BANNER_URL | Framer CMS URL for banner data | https://your-site.framer.app/api/banners/main |
BLOG_URL | nx-blog site URL for blog/changelog pages | https://blog.nx.app |
NX_DEV_URL | Canonical site URL for sitemap | https://nx.dev |
NEXT_PUBLIC_NO_INDEX | Set to true to add noindex robots directive | true |
The sitemap is composed of multiple sources:
/sitemap.xml) - Generated by next-sitemap/sitemap-1.xml) - Proxied via additional-sitemaps.ts edge function/sitemap-2.xml) - Proxied via additional-sitemaps.ts edge function/docs/sitemap-index.xml) - Served by AstroThe sitemap index references these via scripts/patch-sitemap-index.mjs, which runs after next-sitemap generates the index.
nx-dev/nx-dev/_redirects# --- section-name ---)/old-path /new-path 301Example:
# --- myNewSection ---
/old-feature /docs/new-feature 301
/old-feature/* /docs/new-feature/:splat 301
If you need a path to be served by Next.js instead of Framer:
netlify/edge-functions/rewrite-framer-urls.tsnextjsPaths set (for exact matches):
const nextjsPaths = new Set([
'/blog',
'/your-new-path', // Add here
]);
excludedPath in the config export (for patterns):
excludedPath: ['/your-new-path', '/your-new-path/*'];
By default, all paths go to Framer unless excluded. To add a new marketing page:
excludedPath or nextjsPathsscripts/documentation/internal-link-checker.ts framerPaths array for link validationIf a page returns 404:
Check the edge function: Is the path being proxied to Framer when it shouldn't be?
excludedPath in rewrite-framer-urls.tsx-nx-edge-function response headerCheck redirects: Is there a redirect that should match?
_redirects fileCheck Next.js rewrites: Is /docs/* proxying correctly?
NEXT_PUBLIC_ASTRO_URL is setCheck Framer: Does the page exist in Framer?
$NEXT_PUBLIC_FRAMER_URL/your-pathIf client-side navigation works but direct URL access fails:
excludedPathUseful headers to check:
x-nx-edge-function: framer-proxy or framer-sitemap indicates edge function handled the requestx-nf-request-id: Netlify request ID for debugging# Start Next.js dev server
nx serve nx-dev
# The dev server uses NEXT_PUBLIC_ASTRO_URL=https://master--nx-docs.netlify.app by default
Note: Edge functions don't run locally. To test edge function behavior, deploy to a Netlify preview.
Netlify environment variables are baked in at build time. Changing a variable in the Netlify UI (or via CLI) does not take effect until the site is redeployed.
You can trigger a redeployment through the Netlify UI (Deploys > Trigger deploy) or via the Netlify CLI:
# Redeploy the docs site (Astro)
netlify deploy --trigger --prod -s nx-docs
# Redeploy the main site (Next.js)
netlify deploy --trigger --prod -s nx-dev
This is especially important when updating NEXT_PUBLIC_FRAMER_URL, NEXT_PUBLIC_ASTRO_URL, or any other variable referenced at build time.
https://deploy-preview-{PR}--nxdev.netlify.apphttps://deploy-preview-{PR}--nx-docs.netlify.appDuring deploy previews, the Next.js app automatically configures NEXT_PUBLIC_ASTRO_URL to point to the matching Astro preview based on REVIEW_ID.