This guide covers the architecture, deployment, internals, and extension of the Prompt Engineering Guide (PEG) — a Nextra-based documentation site maintained by DAIR.AI. It is written for developers who need to modify, deploy, or understand the codebase. See the User Guide for content navigation and usage.
1. Architecture Overview
What the System Does
The Prompt Engineering Guide is a statically generated, multilingual documentation website built on the Nextra framework (which itself is built on Next.js). The site serves structured educational content about prompt engineering through MDX pages, with interactive React components for code copying, AI assistant integration, and course promotion. The entire content layer is file-based — MDX files in the pages/ directory define both the site structure and the rendered content.
Architecture Diagram
Browser Request
│
▼
┌─────────────┐
│ Next.js │
│ Server │
│ (SSG/SSR) │
├─────────────┤
│ Nextra │ MDX → React pages
│ v2.13.2 │ i18n routing
│ Theme: docs │ Search indexing
├─────────────┤
│ Custom │ AnnouncementBar, CopyPageDropdown,
│ Components │ CourseCard, CodeBlock, Pre,
│ │ TabsComponent, PromptFiles,
│ │ ContentFileNames, Screenshot
├─────────────┤
│ API Routes │ /api/contentFiles
│ (3 routes) │ /api/getPageContent
│ │ /api/promptsFiles
├─────────────┤
│ pages/ │ MDX content (14 locales)
│ (1500+ │ _meta.*.json (navigation)
│ files) │ img/ (static assets)
└─────────────┘
Note
The project is titled
nextra-docs-templateinpackage.json— it was bootstrapped from Nextra's documentation template and customized with DAIR.AI-specific components and content. This has no functional impact but appears in build logs and lock files.
Component Inventory
| Component | Path | Role |
|---|---|---|
| Next.js App | pages/_app.tsx |
Root app with analytics, announcement bar, global CSS |
| Middleware | middleware.js |
Nextra locale detection and routing |
| Next Config | next.config.js |
Nextra plugin config, i18n locales, SVG webpack rules |
| Theme Config | theme.config.tsx |
Site branding, navigation, i18n labels, CopyPageDropdown injection |
| AnnouncementBar | components/AnnouncementBar.tsx |
Top-of-page promotional banner |
| CodeBlock | components/CodeBlock.tsx |
Code display with copy button (FontAwesome icons) |
| ContentFileNames | components/ContentFileNames.tsx |
Dynamic card grid for section content listing |
| CopyPageDropdown | components/CopyPageDropdown.tsx |
Copy-as-markdown, Open in Claude/ChatGPT dropdown |
| CourseCard | components/CourseCard.tsx |
Course promotion cards with dark mode support |
| PromptFiles | components/PromptFiles.jsx |
Dynamic listing of Prompt Hub categories and entries |
| TabsComponent | components/TabsComponent.tsx |
Multi-model API code example tabs |
| Pre | components/pre.tsx |
Custom code block wrapper with word-wrap toggle and copy |
| Screenshot | components/screenshot/index.jsx |
Image display with border and styling |
| Icons | components/icons/index.ts |
SVG icon exports (28 icons) |
| Button | components/button.tsx |
Reusable styled button |
| CopyToClipboard | components/copy-to-clipboard.tsx |
Clipboard copy with visual feedback |
| Copy/Check Icons | components/copy.tsx, components/check.tsx |
SVG icons for copy/check states |
| WordWrap Icon | components/word-wrap.tsx |
SVG icon for word-wrap toggle |
| Counters | components/counters.tsx |
Example React counter component |
Technology Stack
| Layer | Technology | Version |
|---|---|---|
| Framework | Next.js | ^13.5.6 |
| Documentation | Nextra | ^2.13.2 |
| Theme | nextra-theme-docs | ^2.13.2 |
| UI | React | ^18.2.0 |
| Language | TypeScript | ^4.9.5 |
| Icons (code blocks) | FontAwesome | ^6.5.1 |
| Icons (SVG components) | @svgr/webpack | ^8.1.0 |
| Git info | @napi-rs/simple-git | ^0.1.19 |
| Analytics | @vercel/analytics | ^0.1.11 |
| Math rendering | KaTeX | ^0.16.27 |
| Utility | clsx | ^2.1.0 |
2. System Requirements
Build Requirements
| Requirement | Minimum |
|---|---|
| Node.js | 16+ (Next.js 13 requirement) |
| Package Manager | npm or pnpm |
| Disk Space | ~500 MB (including node_modules) |
| Memory | 4 GB RAM recommended for build |
Development
# Clone the repository
git clone https://github.com/dair-ai/Prompt-Engineering-Guide.git
cd Prompt-Engineering-Guide
# Install dependencies
npm install
# or
pnpm install
# Start development server
npm run dev
ready - started server on 0.0.0.0:3000
Important
The project uses
pnpm-lock.yamlalongsidepackage-lock.json. If both are present, ensure you use the same package manager consistently to avoid dependency resolution conflicts.
Build and Production
# Build for production
npm run build
# Start production server
npm start
3. Configuration Reference
next.config.js
The core configuration file applies the Nextra plugin and configures Next.js.
const withNextra = require('nextra')({
theme: 'nextra-theme-docs',
themeConfig: './theme.config.tsx',
latex: true
})
module.exports = withNextra({
i18n: {
locales: ['en', 'zh', 'jp', 'pt', 'tr', 'es', 'it', 'fr', 'kr', 'ca', 'fi', 'ru', 'de', 'ar'],
defaultLocale: 'en',
},
webpack(config) {
// SVG handling for components/icons/
const allowedSvgRegex = /components\/icons\/.+\.svg$/
const fileLoaderRule = config.module.rules.find(rule => rule.test?.test?.('.svg'))
fileLoaderRule.exclude = allowedSvgRegex
config.module.rules.push({
test: allowedSvgRegex,
use: ['@svgr/webpack']
})
return config
}
})
| Setting | Value | Purpose |
|---|---|---|
theme |
nextra-theme-docs |
Nextra documentation theme |
themeConfig |
./theme.config.tsx |
Theme customization file |
latex |
true |
Enables KaTeX rendering in MDX |
i18n.locales |
14 locale codes | Supported languages |
i18n.defaultLocale |
en |
Default language |
| SVG webpack rule | @svgr/webpack |
Allows importing SVGs in components/icons/ as React components |
theme.config.tsx
Controls site branding, navigation, and layout customization.
| Setting | Value | Purpose |
|---|---|---|
logo |
SVG + "Prompt Engineering Guide" text | Site logo with three-dot icon |
i18n |
Array of 14 locale objects | Language selector labels |
head |
Custom <head> with OG tags, favicon |
SEO and favicon configuration |
project.link |
GitHub repo URL | GitHub link in header |
chat.link |
Discord invite URL | Discord link in header |
docsRepositoryBase |
GitHub tree URL | "Edit this page" link base |
footer.text |
"Copyright 2026 DAIR.AI" | Footer content |
search.placeholder |
"Search..." | Search bar placeholder |
gitTimestamp |
Custom component with SerpAPI sponsor | Last-updated display with sponsor logo |
components.pre |
Custom Pre component |
Replaces default code blocks with copy/word-wrap |
main |
Custom wrapper | Injects CopyPageDropdown on English non-index pages |
navbar.extraContent |
"Services" button | Purple CTA button in navbar |
Important
The
mainwrapper conditionally rendersCopyPageDropdownonly whenrouter.locale === 'en'androuter.pathname !== '/'. Modifying locale routing logic may break this feature.
Google Analytics
Analytics are configured directly in pages/_app.tsx:
<Script async src="https://www.googletagmanager.com/gtag/js?id=G-ST7R3WQ353"/>
Tracking ID: G-ST7R3WQ353
Vercel Analytics is also enabled via @vercel/analytics/react.
4. Deployment & Scaling
Build Pipeline
The standard Next.js build process applies:
npm run build # Generates .next/ directory
npm start # Starts production server
The site is designed for deployment on Vercel (evidenced by @vercel/analytics integration and Nextra's Vercel-optimized defaults), but can be deployed to any platform that supports Next.js.
Static Export Considerations
Nextra with i18n enabled requires server-side rendering for locale detection (via middleware.js). A fully static export (next export) is not supported with the current configuration due to:
- The
i18nconfiguration innext.config.js - The API routes in
pages/api/ - The middleware-based locale routing
Warning
Do not attempt
next exportwith this configuration. The middleware and API routes require a Node.js runtime.
Deployment Checklist
- [ ] All dependencies installed (
npm install) - [ ] Build completes without errors (
npm run build) - [ ] Verify search works on production URL
- [ ] Verify locale switching works
- [ ] Verify CopyPageDropdown works on English pages
- [ ] Verify LaTeX/KaTeX rendering on research pages
- [ ] Confirm Google Analytics is receiving events
5. Operations
Content Updates
Content is managed entirely through MDX files. The update workflow:
- Edit or add
.mdxfiles in the appropriatepages/subdirectory - Add corresponding
_meta.*.jsonentries for navigation - Test locally with
npm run dev - Commit and push — deployment handles the rest
Adding a New Content Page
-
Create the MDX file with the locale suffix:
pages/techniques/new-technique.en.mdx -
Add the page to the English navigation metadata:
// pages/techniques/_meta.en.json { "new-technique": "New Technique Name" } -
For translations, create locale-specific files and metadata:
pages/techniques/new-technique.zh.mdx pages/techniques/new-technique.de.mdx
Tip
You only need to add metadata entries for languages where a translation exists. Nextra gracefully handles missing translations by not showing those pages in the sidebar for that locale.
Adding a New Language
-
Add the locale code to
next.config.js:i18n: { locales: ['en', 'zh', /* ... */, 'new-locale'], defaultLocale: 'en', } -
Add the locale label to
theme.config.tsx:i18n: [ // ... existing locales { locale: 'new-locale', text: 'Language Name' }, ] -
Create
_meta.new-locale.jsonfiles in each section directory -
Create
.new-locale.mdxcontent files
Monitoring
- Google Analytics (G-ST7R3WQ353) — page views, user geography, session data
- Vercel Analytics — web vitals, performance metrics (if deployed on Vercel)
- Git timestamps — each page shows its last update date via
@napi-rs/simple-git
Note
The
@napi-rs/simple-gitdependency enables the "Last updated on" timestamp feature. It reads git history for each file. If the git history is shallow (e.g.,--depth 1clone), timestamps may be inaccurate or missing.
6. Performance
Build Performance
With 1,556 files across 14 locales, build times can be significant. Key factors:
| Factor | Impact |
|---|---|
| Number of locales | Linear — each locale multiplies page count |
| MDX compilation | KaTeX-enabled pages are slower to compile |
| SVG processing | @svgr/webpack adds overhead for icon imports |
| Package lock size | package-lock.json is large due to Nextra's dependency tree |
Runtime Performance
- Static generation — most pages are statically generated at build time
- API routes —
contentFiles,promptsFiles, andgetPageContentrun on the server and read the filesystem at request time - Client-side — CopyPageDropdown fetches page content from GitHub raw URLs via the
/api/getPageContentroute
Tip
The
/api/getPageContentroute fetches content fromhttps://raw.githubusercontent.com/dair-ai/Prompt-Engineering-Guide/main/pages/at request time. This means the "Copy page" feature always serves the latestmainbranch content, not the deployed version.
7. Security
API Route Input Validation
The three API routes perform basic input validation:
/api/getPageContent — the most security-sensitive route:
- Validates
pagePathparameter exists and is a string - Restricts to
.en.mdxfiles only (hardcoded) - Constructs URLs from user input — path traversal is mitigated by the
.en.mdxsuffix requirement and GitHub's own URL validation - Fetches from a hardcoded GitHub raw URL base
/api/contentFiles and /api/promptsFiles — read local filesystem:
- Accept
sectionandlangparameters - Construct filesystem paths using
path.join(process.cwd(), 'pages', section) - No explicit sanitization of the
sectionparameter — directory traversal is limited by Next.js's API route sandboxing and the fact thatfs.existsSync/fs.readdirSyncwould fail for non-existent paths
Warning
The
sectionparameter in/api/contentFilesis used directly inpath.joinwithout sanitization. While Next.js provides some protection, a defense-in-depth approach would validate thatsectioncontains no..or path separators. This is low-risk in practice since the API only reads metadata files.
Third-Party Scripts
| Script | Purpose | Privacy Impact |
|---|---|---|
Google Analytics (G-ST7R3WQ353) |
Usage tracking | Sends page views and user data to Google |
| Vercel Analytics | Performance monitoring | Sends web vitals to Vercel |
| SerpAPI logo | Sponsor attribution | External image load from cdn.rawgit.com |
External Data Flows
| Feature | External Call | Data Sent |
|---|---|---|
| Copy page / Open in Claude | /api/getPageContent then GitHub raw |
Page path |
| Open in Claude | Redirects to claude.ai |
Current page URL in prompt |
| Open in ChatGPT | Redirects to chatgpt.com |
Current page URL in prompt |
| Course links | Redirects to academy.dair.ai |
None (navigation only) |
Caution
The "Open in Claude" and "Open in ChatGPT" features construct URLs that include the current page's URL. Ensure no sensitive internal routes are accidentally exposed through this mechanism.
8. Developer Internals
Repository Structure
Prompt-Engineering-Guide/
├── middleware.js # Nextra locale routing
├── next.config.js # Next.js + Nextra configuration
├── theme.config.tsx # Site theme and branding
├── package.json # Dependencies and scripts
├── tsconfig.json # TypeScript configuration
├── CITATION.cff # Academic citation metadata
├── LICENSE.md # MIT License
├── components/ # React components
│ ├── AnnouncementBar.tsx # Promotional banner
│ ├── CodeBlock.tsx # Code display with copy
│ ├── ContentFileNames.tsx # Dynamic content card grid
│ ├── CopyPageDropdown.tsx # AI integration dropdown
│ ├── CourseCard.tsx # Course promotion cards
│ ├── PromptFiles.jsx # Prompt Hub listing
│ ├── TabsComponent.tsx # Multi-model code tabs
│ ├── button.tsx # Reusable button
│ ├── check.tsx # Check icon SVG
│ ├── copy.tsx # Copy icon SVG
│ ├── copy-to-clipboard.tsx # Clipboard utility
│ ├── counters.tsx # Example counter
│ ├── pre.tsx # Custom code block
│ ├── word-wrap.tsx # Word-wrap icon SVG
│ ├── counters.module.css # Counter styles
│ ├── icons/ # SVG icons (28 files)
│ │ └── index.ts # Icon barrel exports
│ └── screenshot/ # Screenshot component
│ └── index.jsx # Image display
├── pages/ # Content and routing
│ ├── _app.tsx # App root (analytics, announcement bar)
│ ├── style.css # Global styles
│ ├── _meta.*.json # Navigation metadata (per locale)
│ ├── index.*.mdx # Homepage (per locale)
│ ├── about.*.mdx # About page
│ ├── api/ # API routes
│ │ ├── contentFiles.js # Section content listing
│ │ ├── getPageContent.ts # Fetch page markdown from GitHub
│ │ └── promptsFiles.js # Prompt Hub category listing
│ ├── introduction/ # Introduction section
│ ├── techniques/ # Prompting techniques
│ ├── agents/ # AI Agents (English only)
│ ├── guides/ # Topical guides (English only)
│ ├── applications/ # Application guides
│ ├── prompts/ # Prompt Hub
│ ├── models/ # Model guides
│ ├── risks/ # Risks & Misuses
│ └── research/ # Research findings
├── guides/ # Legacy markdown guides
├── notebooks/ # Jupyter notebooks (13 files)
├── img/ # Static images
├── lecture/ # Lecture PDF
├── ar-pages/ # Arabic locale pages
└── public/ # Static assets (favicons)
Content File Naming Convention
All content files follow a strict naming pattern:
{page-slug}.{locale}.mdx
Examples:
pages/techniques/cot.en.mdx— Chain-of-Thought page, Englishpages/techniques/cot.zh.mdx— Chain-of-Thought page, Chinesepages/techniques/cot.de.mdx— Chain-of-Thought page, German
Navigation metadata follows the same pattern:
_meta.{locale}.json
Each _meta.*.json file maps page slugs to display titles for that locale:
{
"cot": "Chain-of-Thought Prompting",
"fewshot": "Few-shot Prompting"
}
Note
Arabic (
ar) uses a different directory structure — content lives inar-pages/rather than withinpages/. Arabic-locale metadata files use the.ar.jsonand.ar.mdxsuffixes but are in a separate directory tree. This is an architectural inconsistency — all other locales coexist withinpages/.
API Routes
GET /api/contentFiles
Returns ordered page listings for a given section and locale.
| Parameter | Type | Default | Description |
|---|---|---|---|
section |
string | research |
Directory name under pages/ |
lang |
string | en |
Locale code |
Response: { fileNames: [{ slug, title }] }
Reads _meta.{lang}.json from the specified section directory and returns page slugs with their titles in metadata-defined order.
GET /api/getPageContent
Fetches cleaned markdown content from GitHub.
| Parameter | Type | Required | Description |
|---|---|---|---|
pagePath |
string | Yes | Path to the .en.mdx file relative to pages/ |
Response: { content, pagePath }
Processing steps:
- Validates that
pagePathends with.en.mdx - Fetches raw content from
https://raw.githubusercontent.com/dair-ai/Prompt-Engineering-Guide/main/pages/{pagePath} - Strips
importstatements,exportstatements, and YAML frontmatter - Returns cleaned markdown
GET /api/promptsFiles
Returns the complete Prompt Hub structure.
| Parameter | Type | Default | Description |
|---|---|---|---|
lang |
string | en |
Locale code |
Response: Array of { folderKey, folderName, files: [{ slug, title }] }
Reads the prompts directory structure and returns category folders with their page listings.
Component Architecture
CopyPageDropdown
The most complex component — provides AI integration features.
Rendering logic: Injected into every English non-index page via theme.config.tsx's main wrapper.
State management:
isOpen— dropdown visibilityshowMarkdownModal— markdown preview modalmarkdownContent— fetched page contentcopyStatus—idle|copying|successhoveredButton— hover state for styling
Clipboard implementation: Two-tier approach:
- Modern
navigator.clipboard.writeText()for HTTPS contexts - Fallback using
document.execCommand('copy')with iOS-specific handling (selection range, 16px font to prevent zoom)
External redirects:
- Claude:
https://claude.ai/new?q={encoded_prompt} - ChatGPT:
https://chatgpt.com/?prompt={encoded_prompt}
CourseCard System
Three exported components for course promotion:
CourseCard— individual course card with tag, title, description, metadataCoursesSection— grid container for multiple CourseCardsCoursePromo— single-card inline promotion with CTA button
All three support dark mode via a useDarkMode hook that observes document.documentElement.classList for the dark class.
Pre Component
Replaces Nextra's default <pre> element via theme.config.tsx:
components: {
pre: Pre,
}
Features:
- Word-wrap toggle (persisted via
document.documentElement.dataset.nextraWordWrap) - Copy-to-clipboard (reads from the rendered
<code>element'stextContent) - Optional filename header display
ContentFileNames and PromptFiles
Dynamic components that fetch navigation data from the API routes and render Nextra Cards:
ContentFileNames— fetches/api/contentFilesand renders a card grid for a sectionPromptFiles— fetches/api/promptsFilesand renders categorized prompt listings with section headers
Internationalization Deep Dive
The i18n system has three layers:
- Next.js i18n routing (
next.config.js) — handles URL locale prefixes and detection - Nextra locale middleware (
middleware.js) —export { locales as middleware } from 'nextra/locales' - Theme i18n labels (
theme.config.tsx) — maps locale codes to display names for the language selector
Content resolution order:
- Look for
{slug}.{locale}.mdxin the current section - If not found, the page is not shown in the sidebar for that locale
- There is no fallback to English — missing translations are simply absent
Metadata resolution:
- Look for
_meta.{locale}.jsonin the section directory - Pages without metadata entries are still accessible by URL but not shown in navigation
Code Patterns and Conventions
| Pattern | Usage |
|---|---|
| Client-side dark mode detection | document.documentElement.classList.contains('dark') via MutationObserver |
| Inline styles over CSS classes | Most components use React style props; only Nextra utility classes (nx-*) are used for theme-consistent styling |
| Hover state management | onMouseOver / onMouseOut handlers with direct style mutation |
| Data fetching | Client-side fetch() in useEffect hooks; no SWR or React Query |
| TypeScript strictness | Mixed — some components are .tsx (typed), some are .jsx (untyped) |
| State management | Local React useState only; no global state management library |
| SVG icons | Two systems — @svgr/webpack for components/icons/*.svg, FontAwesome for code block copy buttons |
Note
The codebase uses two different icon systems (SVGR and FontAwesome) and two different clipboard implementations (the
CopyToClipboardcomponent and theCopyPageDropdown's inline implementation). This is a historical artifact, not a deliberate architectural choice.
Testing
No test files or test configuration were found in the repository. The package.json does not include a test script, and no testing framework (Jest, Vitest, Playwright, Cypress) is present in dependencies.
Warning
The project has no automated tests. Changes to components, API routes, or configuration should be manually verified in the development server across multiple locales before deployment.
Potential Improvements
Based on source analysis:
- Input sanitization for API routes — the
sectionparameter in/api/contentFilesshould be validated against an allowlist of known section names - Consolidate icon systems — unify on either SVGR or FontAwesome, not both
- Consolidate clipboard implementations — the
CopyToClipboardcomponent andCopyPageDropdown's inline clipboard code could share a utility - Add TypeScript to
.jsxcomponents —PromptFiles.jsxandscreenshot/index.jsxlack type annotations - Arabic content directory — consider migrating
ar-pages/into the standardpages/directory with.ar.mdxsuffixes for consistency - Stale GitHub fetch in
getPageContent— fetching from GitHub'smainbranch at request time means the "Copy page" content may differ from the deployed version; consider reading from the local filesystem instead - Add automated testing — at minimum, smoke tests for API routes and critical component rendering
9. Integration Points
External Services
| Service | Integration Point | Purpose |
|---|---|---|
| GitHub | Repository hosting, getPageContent API |
Source code, raw content serving |
| Vercel | Deployment platform (implied) | Hosting, analytics |
| Google Analytics | _app.tsx script tag |
Usage tracking |
| SerpAPI | Sponsor logo in git timestamp footer | Sponsorship attribution |
| DAIR.AI Academy | Course links in navbar and CourseCard components | Paid course promotion |
| Discord | Chat link in theme config | Community support |
Content Pipeline
MDX files → Nextra MDX compiler → React pages → Static HTML (build)
→ Server-rendered (API routes)
The content pipeline is entirely file-based:
- Authors write or edit
.mdxfiles - Navigation structure is defined in
_meta.*.jsonfiles - Nextra compiles MDX to React components at build time
- The search index is built automatically by Nextra
- Git timestamps provide "last updated" dates
Adding New Sections
To add a top-level section (e.g., "Benchmarks"):
- Create the directory:
pages/benchmarks/ - Add metadata for each supported locale:
// pages/benchmarks/_meta.en.json { "overview": "Benchmarks Overview" } - Add content files:
pages/benchmarks/overview.en.mdx - Register in the top-level navigation metadata:
// pages/_meta.en.json (add the key) { "benchmarks": "Benchmarks" } - Repeat metadata entries for other locales as translations become available
10. Contributing
Prerequisites
- Node.js 16+
- Git
- Familiarity with MDX (Markdown + JSX)
Development Workflow
- Fork and clone the repository
- Install dependencies:
npm install - Create a feature branch
- Make changes
- Test locally:
npm run dev - Verify across at least 2 locales (English + one other)
- Submit a pull request
Content Contribution Guidelines
- Write content in MDX format
- Follow existing page structure for consistency
- Add
_meta.*.jsonentries for new pages - Include images in the appropriate
img/subdirectory - Test LaTeX rendering if mathematical notation is used
Component Contribution Guidelines
- Use TypeScript (
.tsx) for new components - Follow the existing inline-style pattern (or propose a migration to CSS modules)
- Support dark mode using the
useDarkModepattern fromCourseCard.tsx - Test in both light and dark modes
- Verify mobile responsiveness
Open Community Issues
From GitHub issues (as of source commit):
| Issue | Topic |
|---|---|
| #749 | Feedback for Introduction section |
| #741 | Homepage should define what a prompt is |
| #738 | Feedback for Meta Prompting |
| #734 | Korean translation — remaining untranslated pages |
| #724 | Feedback for Prompt Chaining |
| #702 | Feedback: unlisted technique, potential naming conflict with meta-prompting |
| #743 | Feature request: add StoryRoute AI app |
| #742 | Resource suggestion: ORCH CLI for multi-agent teams |
| #730 | Suggestion: reference WFGY problem map in RAG sections |