Share a MkDocs Site With Your Team (No GitHub Account Required)
MkDocs builds clean, well-formatted documentation sites from Markdown (MkDocs docs). The build output in `./site/` is a static directory that renders in any browser. The problem is never building the docs. It's getting t

MkDocs builds clean, well-formatted documentation sites from Markdown (MkDocs docs). The build output in ./site/ is a static directory that renders in any browser. The problem is never building the docs. It's getting them in front of the PM, the designer, or the support lead who needs to read them but doesn't live in your GitHub repo.
This guide publishes the built site at a company-authenticated URL that never changes, so anyone with a company email can read it, and nobody needs a GitHub seat.
Why the usual options don't fit internal docs
- GitHub Pages (public): Anyone on the internet can read it. Wrong for internal engineering docs.
- GitHub Pages (private repos): Requires GitHub Enterprise Cloud, and every viewer needs a GitHub account with repo access (GitHub Pages docs). At $21/user/month, 100 readers is $2,100/month.
- Confluence: You'd manually recreate the content, and the Markdown-to-wiki round trip strips formatting and code blocks.
- Read the Docs: Sphinx-oriented; MkDocs works but you inherit their build and their hosting model.
- Raw Markdown in the repo: Your PM reads unrendered
.mdfiles with broken links and unstyled tables.
Setup
pip install mkdocs mkdocs-material
mkdocs build
dsp publish ./site/ --name "engineering-docs"Share the URL in your onboarding docs, company Notion, or Slack. Anyone with a company email clicks it, authenticates once, and reads the full rendered MkDocs site: navigation sidebar, client-side search, code highlighting, all of it. On Pro that sign-in is one click via Google or Microsoft SSO; on the Free plan viewers verify with a one-time passcode (a six-digit code by email).
Comparison
| GitHub Pages (private) | Confluence | display.dev | |
|---|---|---|---|
| Renders a built MkDocs site as-is | ✅ | ❌ (manual re-entry) | ✅ |
| Viewer needs a GitHub account | ✅ | ❌ | ❌ |
| Company SSO for viewers | Via Enterprise | ✅ | ✅ (Pro) |
| Setup time | Hours + admin | Migration effort | ~15 min |
| Monthly cost (100 readers) | ~$2,100 | Per-seat | €49 flat |
| Client-side search works | ✅ | N/A | ✅ |
Auto-deploy on push to main
name: Deploy Docs
on:
push:
branches: [main]
paths: ['docs/**', 'mkdocs.yml']
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: pip install mkdocs mkdocs-material
- name: Build docs
run: mkdocs build
- name: Publish docs
run: |
npm install -g @displaydev/cli
BASE_VERSION=$(dsp get "${{ vars.DISPLAY_ARTIFACT_ID }}" | jq -r .currentVersion)
dsp publish ./site/ --id "${{ vars.DISPLAY_ARTIFACT_ID }}" --base-version "$BASE_VERSION"
env:
DISPLAYDEV_API_KEY: ${{ secrets.DISPLAYDEV_API_KEY }}Every push that touches docs/ or mkdocs.yml rebuilds and republishes to the artifact ID stored in DISPLAY_ARTIFACT_ID. The URL stays the same, so bookmarks don't break. --base-version prevents a concurrent publish from being overwritten silently. For the general CI pattern, see publishing HTML from GitHub Actions.
Works with Docusaurus, Sphinx, and Quarto too
npm run build # Output: ./build/
dsp publish ./build/ --name "product-docs"
make html # Output: ./_build/html/
dsp publish ./_build/html/ --name "api-reference"Any static site generator that emits a directory of HTML works with dsp publish ./output-dir/. For notebook-based docs, see share a Quarto report with your team.
Getting links right when served at a subpath
display.dev serves a published site at a path like /0kzNYG7O-engineering-docs/, not at the domain root. MkDocs handles this cleanly if you leave use_directory_urls: true (the default), because it emits relative links between pages. Two things to check in mkdocs.yml:
- Don't hard-code an absolute
site_urlthat assumes the root. Leavesite_urlunset or set it to the published artifact URL so the sitemap and canonical tags match where the docs actually live. - Keep asset references relative. Material for MkDocs does this by default. If you added custom
extra_cssorextra_javascript, use relative paths (css/extra.css), not absolute ones (/css/extra.css), so they resolve under the subpath.
If something links to /, it will jump out of the artifact. Relative links keep navigation inside the published site.
FAQ
Does MkDocs search work after publishing?
Yes. MkDocs generates a search_index.json file in the build output. display.dev serves the whole ./site/ directory, including that index, so client-side search runs in the browser exactly as it does locally.
What if we have multiple doc sites (one per project)?
Publish each with a different name: dsp publish ./api/site/ --name "api-docs" and dsp publish ./platform/site/ --name "platform-docs". Each gets its own URL, and you can link between them with absolute URLs.
How is this different from just using GitHub Pages?
GitHub Pages public serves to the entire internet, which is wrong for internal docs. GitHub Pages private needs Enterprise Cloud and a GitHub account per viewer. display.dev is €49/month flat, any @yourcompany.com email gets in, and no reader needs a GitHub account.
Can non-engineers read it without any tooling?
Yes. They click the link and sign in with their company Google or Microsoft account (Pro) or a one-time passcode (Free). There's nothing to install and no terminal involved.
Does the URL change when I rebuild the docs?
No. When you republish with --id, the artifact updates in place and the URL stays the same. Every rebuild is kept as a version in history (10 on Solo, 50 on Pro).
Free tier. No credit card. One-time password auth for viewers on free, Google + Microsoft SSO on Pro (€49/month flat).