---
title: Host under a sub-path (base URL)
description: "Serve a Pennington site from a non-root URL by passing `[baseUrl]` to the build and letting `BaseUrlHtmlRewriter` prefix every internal href, src, and action."
canonical_url: https://usepennington.net/how-to/deployment/base-url/
sidecar_url: https://usepennington.net/how-to/deployment/base-url.md
content_hash: sha256:e9305098fdf42449a3a0a7ff4baceaabb46240fd5f59a6fa6ad32f7cb475747b
tokens: 945
uid: how-to.deployment.base-url
reading_time_minutes: 3
---

Guides
# Host under a sub-path (base URL)

Serve a Pennington site from a non-root URL by passing `[baseUrl]` to the build and letting `BaseUrlHtmlRewriter` prefix every internal href, src, and action.

 
To serve under a sub-path, pass it as the first argument to `build`. `BaseUrlHtmlRewriter` prefixes every root-relative `href`, `src`, and `action` on the way out; the same `RunOrBuildAsync` call handles root and sub-path identically.

 
## Before you begin

 
 - A working Pennington site that builds locally with `dotnet run -- build` (see [Build a static site](https://usepennington.net/how-to/deployment/static-build.md) if not).
 - **The sub-path the host will serve from** — for example `/docs` for `https://example.com/docs/` or `/<repo>` for a GitHub Pages project site.
 - Internal links authored as root-relative (`/guides/first-page/`). The rewriter only matches the leading `/`; protocol-relative (`//cdn.example.com/x.js`), absolute (`https://…`), hash (`#section`), and page-relative (`./neighbor/`) links pass through untouched.
 - The host is already configured to serve `output/` at that sub-path (see [Deploy to GitHub Pages](https://usepennington.net/how-to/deployment/github-pages.md) or [Self-host behind Nginx or IIS](https://usepennington.net/how-to/deployment/self-host.md)).
 
 
For a working setup, see [examples/SubPathDeployableExample](https://github.com/usepennington/pennington/tree/main/examples/SubPathDeployableExample).

 
## Build with the prefix

 
Pass the sub-path as the `--base-url` flag. Include the leading slash and omit the trailing slash — the rewriter normalizes either way.

 
```bash
dotnet run -- build --base-url=/docs
```

 
For the positional form and the rest of the argument grammar, see [CLI and build arguments](https://usepennington.net/reference/host/cli.md).

 
## Reproduce the prefix from client-side code

 
When an island, Blazor component, or custom script builds URLs at runtime, read the prefix from `document.body.dataset.baseUrl` (stamped by the rewriter) instead of hard-coding `/docs`. The same `output/` then runs under `/docs` in staging and `/` in preview with only a different `--base-url`.

 
```javascript
const base = document.body.dataset.baseUrl ?? "";
const href = `${base}/guides/first-page/`;
```

 
---

 
## Verify

 
 - Run `dotnet run -- build --base-url=/docs` and open `output/index.html` — every internal `href`, `src`, and `action` now starts with `/docs/`, and `<body>` carries `data-base-url="/docs"`.
 - Serve the build so the prefix is part of the path. A static server roots at `/`, so place `output/` inside a folder named for the prefix and serve the parent: `mkdir -p site/docs && cp -r output/* site/docs/ && npx http-server site -p 5000`. Open `http://localhost:5000/docs/` — deep links like `/docs/guides/first-page/` resolve and their in-page links stay under the prefix.
 - Re-run with no `--base-url` — the generated HTML reverts to root-relative paths with no `data-base-url` attribute, confirming the rewriter short-circuits when the prefix is empty or `/`.
 
 
## Related

 
 - Reference: [CLI and build arguments](https://usepennington.net/reference/host/cli.md) — the `build [baseUrl] [outputDirectory]` surface this page drives.
 - Background: [The response-processing pipeline](https://usepennington.net/explanation/core/response-processing.md) — why base-URL rewriting runs at `Order => 30`, after xref and locale rewriters.
 - Background: [Dev mode and build mode share one code path](https://usepennington.net/explanation/core/dev-vs-build.md) — why the same rewriter runs identically in `dotnet run` and `dotnet run -- build`.
 
 
[Previous
                
                Self-host behind Nginx or IIS](https://usepennington.net/how-to/deployment/self-host.md)