This is the official website for Docling.
Install the required dependencies:
uv syncStart the development server on http://0.0.0.0:5001
uv run website/main.pyWhen you make changes to your project, the server will automatically reload.
The site is fully static — every page is pre-rendered to HTML — so it can be published on GitHub Pages (or any static host). Build it with:
uv run website/build.pyThis renders all pages and copies the assets into dist/. To serve that build
locally:
python3 -m http.server 8000 --directory dist
# open http://localhost:8000Any static file server works. Clean URLs such as /deployments/ resolve because
each route is written as <route>/index.html.
Useful options:
--out <dir>: output directory (defaultdist).--base-path <prefix>: URL prefix for root-relative links, needed when the site is served from a sub-path. For the GitHub project page atdocling-project.github.io/website, build with--base-path /website(the repository name). Leave empty for a root/custom-domain deploy.--cname <domain>: write aCNAMEfile for a custom domain (e.g.docling.ai).
To preview a sub-path build locally, build straight into a directory whose name
matches the prefix — --base-path rewrites the links but does not nest the
files:
uv run website/build.py --out /tmp/site/website --base-path /website
python3 -m http.server 5055 --directory /tmp/site
# open http://localhost:5055/website/--base-path rewrites root-relative href/src attributes in HTML only, so a
root-relative url() inside a stylesheet would 404 on a sub-path deploy. Write
stylesheet asset URLs relative to the stylesheet instead:
src: url("../font/plex.woff2"); /* not url("/font/plex.woff2") */The build enforces this: it exits with an error naming the file and URL if a
root-relative url() appears in any stylesheet.
Pages are composed from reusable components; content lives in plain Python data modules so copy can be edited without touching markup.
website/
pages/ one module per route — section composition only
components/ reusable product components (hero, document demo, ...)
data/ site content: navigation, samples, product copy, integrations
highlight.py build-time Pygments highlighting (no client-side highlighter)
seo.py sitemap.xml and robots.txt, generated from one route list
public/
css/ cascade layers: tokens, reset, base, layout, components, pages
js/ ES modules, one per concern, loaded via js/main.js
font/ self-hosted IBM Plex Sans (variable) and Plex Mono
CSS uses cascade layers, declared once at the top of css/tokens.css:
@layer reset, tokens, base, layout, components, pages, utilities;Because the order is declared there, the <link> tags can be reordered without
changing which rules win. Colour, spacing, typography and motion are all tokens
in tokens.css; the theme is dark by default with a full light variant under
prefers-color-scheme: light.
Adding a route means adding it in three places: a page module under
website/pages/, a handler in website/main.py, and a _write_page call in
website/build.py. Add it to STATIC_ROUTES in website/seo.py so it reaches
the sitemap.
Sample output shown on the site carries provenance metadata in
website/data/samples.py, including whether it has been regenerated against a
pinned Docling release. Anything not yet reproduced is labelled as such on the
page rather than presented as a verified result.
Pushes to main are built and deployed to GitHub Pages automatically by
.github/workflows/deploy.yml and served at
docling.ai. The workflow builds at the root (BASE_PATH=/)
and writes a CNAME for the custom domain.
Requires, once: Settings → Pages → Build and deployment → Source: GitHub Actions, and the custom domain configured under Settings → Pages → Custom domain.
To serve from docling-project.github.io/website rather than the custom domain,
override the defaults via repository variables under
Settings → Secrets and variables → Actions → Variables:
BASE_PATH=/websiteCNAME= (empty)
This website is part of the Docling project. Your feedback and contributions are welcome!
Writing a Blog Post
Blog posts follow a structured format with timestamped folders and organized assets:
blog/
└── YYYYMMDD_HH_post-title/
├── post.md
└── images/
├── thumbnail.jpg
└── other-images.jpg
-
Create the folder using the naming convention
YYYYMMDD_HH_<title-with-dashes>:mkdir -p blog/20260306_14_my-awesome-post/images
-
Create
post.mdwith metadata and content:--- title: My Awesome Post date: 06-03-2026 summary: A brief description that appears in the blog listing thumbnail: images/thumbnail.jpg --- Your blog content starts here... ## Section Heading You can use all standard Markdown features, code blocks, images, etc. 
-
Add images to the
images/folder:- Thumbnail:
images/thumbnail.jpg(recommended size: 1200x630px) - Other images: Reference them in your post as
images/your-image.jpg
- Thumbnail:
-
Restart the server to see your changes (due to caching):
uv run website/main.py
title: The post title (displayed as H1)date: Publication date inDD-MM-YYYYformatsummary: Brief description shown in blog listingthumbnail: Path to thumbnail image (optional, relative to post folder)category: Post category for filtering (default:technical)technical- Technical guides, tutorials, and deep divesevent- Announcements about events, conferences, or community gatheringsnew-feature-alert- Announcements of new features or releases
The blog supports extended Markdown features including:
- Code syntax highlighting
- Tables
- Footnotes
- Emoji
- Admonitions/callouts
- And more (see
blog/template/post.mdfor examples)
- Use the template at
blog/template/post.mdas a reference - Posts are sorted by date (newest first)
- The folder name's timestamp helps with organization but doesn't affect display
- Images are served from
/blog/<folder-name>/images/
This project is part of the Docling ecosystem. See the main Docling repository for license information.