Project Structure

Where everything lives in a Foundry project and what each file does.

Overview

A Foundry project has two main layers: your app (what you customize) and the Foundry layer (what you extend). You edit your app; Foundry provides the framework.

my-project/
├── app/
│   ├── app.config.ts            # App title, collections, routing, logo
│   ├── assets/
│   │   └── theme.css            # Brand colors (oklch)
│   └── components/
│       └── section/             # Override landing page sections
│           └── Hero.vue         # Custom hero (overrides layer default)
│
├── content/
│   ├── config/
│   │   ├── navigation.yml       # Header, footer, banner links
│   │   └── site.yml             # Business name, socials, mission
│   ├── faq/                     # FAQ entries (YAML)
│   ├── pages/
│   │   ├── index.md             # Landing page
│   │   ├── about.md             # About page
│   │   ├── offers/              # Offer detail pages
│   │   └── success/             # Post-conversion pages
│   └── team/
│       └── founder.yml          # Team member profiles
│
├── server/
│   └── plugins/
│       └── evlog-drain.ts       # Log drain (Sentry/Axiom/PostHog)
│
├── nuxt.config.ts               # Extends layer, route rules, modules
├── content.config.ts            # Content collection definitions
├── .env                         # Environment variables
└── public/                      # Favicons and static assets

Your App vs The Layer

What You Own

Everything in your project directory is yours to customize:

  • content/ — All page content, configuration, and data. This is where you spend most of your time.
  • app/components/ — Override any layer component by creating a file with the same name and path.
  • app/assets/theme.css — Your brand colors.
  • app/app.config.ts — How collections map to routes, what's searchable, logo paths.
  • nuxt.config.ts — Route rules, module configuration, site metadata.
  • content.config.ts — Which content collections exist and what schemas they use.
  • server/plugins/ — Your log drain and any server-side customizations.

What the Layer Provides

The @incubrain/foundry layer gives you everything else:

  • 4 layoutslanding, default, article, docs
  • 33+ components — signal capture forms, section wrappers, navigation, content display
  • 8+ composables — event tracking, content fetching, navigation, storage
  • 7 modules — config, CSS, events, RSS, changelog, docs, comments
  • Server handlers — webhook delivery, RSS feeds, MCP tools
  • Content schemas — Zod schemas for all 9 collection types

You never need to edit the layer directly. Override what you need from your app.

Key Files Explained

content.config.ts

Defines your content collections and their schemas. Each collection maps a directory of YAML or Markdown files to a typed data source.

content.config.ts
import { defineContentConfig, defineCollection } from '@nuxt/content'
import { basePageSchema, baseFaqSchema } from '@incubrain/foundry/schemas'

export default defineContentConfig({
  collections: {
    pages: defineCollection({
      type: 'page',           // Routable — generates URL paths
      source: {
        include: 'pages/**/*.md',
        prefix: '/',
      },
      schema: basePageSchema,
    }),
    faq: defineCollection({
      type: 'data',           // Data-only — queried but not routed
      source: {
        include: 'faq/*.yml',
      },
      schema: baseFaqSchema,
    }),
  },
})

The schemas are imported from @incubrain/foundry/schemas — this ensures your content files match the shape the layer components expect. See the Content Schemas Reference for all available schemas.

nuxt.config.ts

Your Nuxt configuration. The critical parts are:

nuxt.config.ts
export default defineNuxtConfig({
  // Extend the Foundry layer
  extends: ['@incubrain/foundry'],

  // Add optional modules
  modules: ['nuxt-studio', 'nuxt-llms'],

  // Assign layouts to routes
  routeRules: {
    '/': { appLayout: 'landing' },
    '/about': { appLayout: 'default' },
    '/offers/**': { appLayout: 'article' },
    '/success': { appLayout: 'landing' },
    '/success/**': { appLayout: 'landing' },
  },
})

The routeRules block is how you assign layouts to URL patterns. Every page needs a layout.

app/app.config.ts

Runtime configuration that controls how the layer behaves. The most important section is content.collections which maps collection keys to their names and route prefixes:

app/app.config.ts
export default defineAppConfig({
  title: 'My Product',
  content: {
    collections: {
      pages: { name: 'pages', type: 'page', prefix: '/' },
      faq: { name: 'faq', type: 'data' },
      config: { name: 'config', type: 'data' },
      navigation: { name: 'navigation', type: 'data' },
      searchable: ['pages'],
    },
    defaultAuthor: 'founder',
    routing: {
      offers: '/offers',
      success: '/success',
    },
  },
})

See Configuration for the full shape.

How Nuxt Layers Work

Foundry is distributed as a Nuxt Layer, which means your project files always take priority over the layer's defaults. You can override any component, layout, or composable by creating a file with the same name and path in your app.

For details on how Nuxt Layers work, see the Nuxt Layers documentation.

The Content Directory

Content is the heart of a Foundry project. Here's what each subdirectory does:

DirectoryFormatPurpose
content/config/YAMLSite-wide configuration (business info, navigation)
content/pages/MarkdownRoutable pages (landing, about, offers, success)
content/faq/YAMLFAQ entries grouped by type
content/team/YAMLTeam member profiles
content/decisions/MarkdownOptional changelog/decision log
content/docs/MarkdownOptional documentation pages

All content files are validated against Zod schemas at build time. If a file doesn't match its schema, you'll get a clear error message.

Docs Directory Structure

If you're building documentation, each docs subdirectory requires a navigation.yml file to define its title and icon in the sidebar:

content/docs/
├── 1.getting-started/
│   ├── navigation.yml         # Required for sidebar display
│   ├── 1.introduction.md
│   ├── 2.quickstart.md
│   └── 3.configuration.md
└── 2.content/
    ├── navigation.yml         # Required for sidebar display
    ├── 1.overview.md
    └── 2.pages.md

Each navigation.yml follows this structure:

content/docs/1.getting-started/navigation.yml
title: 'Getting Started'
icon: i-lucide-rocket

Important: Do NOT create index.md files in docs subdirectories — they conflict with navigation.yml. Use numbered files instead (1.introduction.md, 2.quickstart.md, etc.). When navigating to a directory path like /docs/getting-started, the system automatically redirects to the first child page.

Next Steps

Learn how to configure everything in Configuration.