---
title: Scaffold a documentation site with DocSite
description: Stand up the DocSite template on an empty ASP.NET project and let a folder of markdown light up the sidebar.
canonical_url: https://usepennington.net/tutorials/docsite/scaffold/
sidecar_url: https://usepennington.net/tutorials/docsite/scaffold.md
content_hash: sha256:2cdcbbe63ec87225279d6f0bc162f054b15bfda47d1e8e09a123e7de81ff9652
tokens: 2110
uid: tutorials.docsite.scaffold
reading_time_minutes: 5
---

Getting Started
# Scaffold a documentation site with DocSite

Stand up the DocSite template on an empty ASP.NET project and let a folder of markdown light up the sidebar.

 
By the end of this tutorial the DocSite host runs with a "Scaffold Docs" title, GitHub icon, and header/footer chrome — and a folder of markdown pages that show up in the sidebar on their own, with a landing page at the root.

 
`AddDocSite` wires a Divio-style documentation site — host, layout, navigation, styling — into one call; for what the template wires, where the wiring stops, and why DocSite and BlogSite can't share an app, read [what the templates wire for you](https://usepennington.net/explanation/positioning/docsite-positioning.md) first.

 
## Prerequisites

 
The DocSite template ships as a NuGet package built for .NET 10, so the stable .NET 10 SDK is all you need — no preview language flag. The .NET 11 beta SDK only matters if you later extend the pipeline by hand; see [the SDK and the union shim](https://usepennington.net/explanation/positioning/sdk-and-the-union-shim.md).

 
 - .NET 10 SDK installed
 - A terminal and a text editor or IDE
 
 
The finished code for this tutorial lives in [examples/DocSiteScaffoldExample](https://github.com/usepennington/pennington/tree/main/examples/DocSiteScaffoldExample).

 
---

 
## 1. Scaffold a new ASP.NET project

 
Start from an empty ASP.NET web project. DocSite ships everything from routing to the Razor layout, so the project shell is the only scaffolding needed before `AddDocSite`.

 
**Create the web project**

 
```bash
dotnet new web -n DocSiteScaffold
cd DocSiteScaffold
```

 
**Add the Pennington DocSite package**

 
```bash
dotnet add package Pennington.DocSite
```

 
> [!IMPORTANT]
> Pennington is in alpha — check NuGet for the current prerelease and pin every `Pennington.*` package to that same version.

 
> [!CHECKPOINT]
>  - Run `dotnet build` — the empty project with the DocSite package added compiles before you touch `Program.cs`

---

 
## 2. Wire `AddDocSite`, `UseDocSite`, and `RunDocSiteAsync`

 
`AddDocSite` is a single DI call that registers Pennington core, [MonorailCSS](https://monorailcss.github.io/MonorailCss.Framework/), SPA navigation, the content resolver, and the component that renders the page body into the layout — all driven from one options object. `UseDocSite` is its middleware counterpart; `RunDocSiteAsync` dispatches the host between dev-serve and static-build modes (see [CLI and build arguments](https://usepennington.net/reference/host/cli.md) for the args contract).

 
**Replace `Program.cs` with the three DocSite calls**

 
`AddDocSite` takes a function that returns a fresh `DocSiteOptions`, and the template registers the markdown content reader for you — no separate `AddMarkdownContent` call. `RunDocSiteAsync` serves pages live in development and generates static HTML when invoked as `dotnet run -- build`.

 
```csharp:symbol,bodyonly
var builder = WebApplication.CreateBuilder(args);
  
builder.Services.AddDocSite(() => new DocSiteOptions
{
    SiteTitle = "Scaffold Docs",
    SiteDescription = "A minimal DocSite scaffold built on AddDocSite.",
    GitHubUrl = "https://github.com/usepennington/pennington",
    HeaderContent = """<a href="/">Scaffold Docs</a>""",
    FooterContent = """<footer class="mt-16 py-8 text-center text-sm text-base-500">Built with Pennington DocSite.</footer>""",
});
  
var app = builder.Build();
  
app.UseDocSite(); 
  
await app.RunDocSiteAsync(args); 
```

 
The five fields populated here — `SiteTitle`, `SiteDescription`, `GitHubUrl`, `HeaderContent`, `FooterContent` — each surface in the rendered chrome as soon as they're set. `DocSiteOptions` carries many more fields; see [Pennington.DocSite.DocSiteOptions](https://usepennington.net/reference/api/doc-site-options.md) for the full surface, and [What the DocSite and BlogSite templates wire for you](https://usepennington.net/explanation/positioning/docsite-positioning.md) for what the template hard-codes.

 
> [!CHECKPOINT]
>  - Run `dotnet run` and visit `http://localhost:5000/`
>  - The DocSite layout renders: left sidebar, header with site title, search affordance, dark-mode toggle, GitHub icon linking to `GitHubUrl`, and the footer HTML from `FooterContent`

---

 
## 3. Add pages and watch the sidebar fill in

 
DocSite builds the sidebar from the shape of `Content/`. Drop a markdown file into a folder and it becomes a sidebar entry — no routing table, no registration call. A subfolder turns into a navigation group named after the folder.

 
**Create a `guides` folder with a landing page**

 
Under `Content/`, create a `guides/` folder and add an `index.md`. The folder name becomes a **Guides** group in the sidebar, and `index.md` is the page it links to at `/guides/`.

 
```markdown:symbol
---
title: Guides
description: Task walkthroughs and onboarding.
---
  
Walkthroughs and how-tos live in this folder. Every markdown file under
`Content/guides/` shows up as a page in the sidebar — the folder name becomes
the **Guides** group around them.
```

 
**Add two pages inside the folder**

 
Add two more files next to `index.md`. Each carries a `title`, a `description`, and an `order:` — the `order:` decides which sorts first. Dropping the files in the folder is the whole wiring.

 
```markdown:symbol
---
title: Getting started
description: Install the package and run the site.
order: 1
---
  
Every markdown file under `Content/guides/` becomes a sidebar entry — no
routing table, no registration call. This page answers to
`/guides/getting-started`.
  
The folder name becomes the sidebar group; `order:` decides where the page
sorts inside it.
```

 
```markdown:symbol
---
title: Configuration
description: Where DocSite reads its settings.
order: 2
---
  
A second page beside the first. Because it carries `order: 2`, it sorts below
*Getting started* (`order: 1`) under the **Guides** group in the sidebar.
```

 
> [!CHECKPOINT]
>  - Run `dotnet run` and visit `http://localhost:5000/guides/getting-started`
>  - The sidebar shows a **Guides** group with *Getting started* above *Configuration* — sorted by `order:`
>  - The page you're viewing is highlighted in the sidebar; clicking *Configuration* swaps to it instantly

---

 
## 4. Give the root `/` a landing page

 
The pages under `guides/` answer to `/guides/...`, but the root `/` has no page of its own yet — a request to `/` returns a 404. To serve the root, drop a markdown file at `Content/index.md`, next to the `guides/` folder.

 
**Author `Content/index.md`**

 
Use the same [DocSiteFrontMatter](https://usepennington.net/reference/api/doc-site-front-matter.md) shape as any other page. What makes this page the root is its location — `Content/index.md` maps to `/`.

 
```markdown
---
title: Welcome
description: Start here, then pick a guide.
---

Welcome to Scaffold Docs.

- [Getting started](/guides/getting-started) — install and run.
- [Configuration](/guides/configuration) — where settings live.
```

 
> [!CHECKPOINT]
>  - `http://localhost:5000/` returns the rendered `Content/index.md` page inside the DocSite chrome
>  - Both links navigate into the `guides/` pages and highlight them in the sidebar

---

 
## Summary

 
 - An empty ASP.NET project picked up `AddDocSite` + `UseDocSite` + `RunDocSiteAsync`, and the full Razor chrome renders.
 - `DocSiteOptions` carries `SiteTitle`, `SiteDescription`, `GitHubUrl`, `HeaderContent`, and `FooterContent`, and each field appears in the rendered layout.
 - Markdown files under `Content/` become sidebar entries with no extra wiring — a subfolder turns into a navigation group named after the folder, and `order:` sorts the pages inside it.
 - The root `/` is served by `Content/index.md`; without it, `/` returns a 404.
 - To split the sidebar into switchable areas and labeled sections, see [Organize content with sections and areas](https://usepennington.net/tutorials/docsite/sections-and-areas.md). For what the template hard-codes, see [What the DocSite and BlogSite templates wire for you](https://usepennington.net/explanation/positioning/docsite-positioning.md).
 
 
[Previous
                
                Add navigation across your pages](https://usepennington.net/tutorials/getting-started/navigation.md)[Next
                    
                Add doc pages and link between them](https://usepennington.net/tutorials/docsite/first-doc-page.md)