The project website for
afterpythonis created usingafterpythonitself. See the website.
Definition¶
On PyPI, you typically see three urls under Project Links,
and they are defined in the [project.urls] section of pyproject.toml.
Most projects that are not backed by a company either omit the homepage field,
or reuse the documentation URL as the homepage, even though it already has its own link.

PyPI homepage button
Here is where afterpython comes to the rescue:
It automatically generates a project website that serves as the homepage for every Python project,
allowing even small, resource-constrained projects to have a dedicated website.
Essentially, it extends your documentation site into a fully featured website.
Architecture¶
During ap init, afterpython creates a new directory afterpython/_website/ and initializes it with projectmystmd in all of the content folders in afterpython/ (e.g., afterpython/doc/, afterpython/blog/)
This approach brings us into the realm of full-stack web development, which enables us to add features such as an AI chatbot, full-text search engine across the website, etc.
Website Template Update¶
projectafterpython to provide new features and bug fixes for the project website.
When updates are available, run ap update website, which will update afterpython/_website, and you can start using the new features immediately.
Customization and Styling¶
Since all the code is pulled from projectafterpython/_website/, you can customize the project website by modifying the code in afterpython/_website/src/.
Landing Page¶
For example, to change the landing page, which by default displays the README.md, you can modify the code in afterpython/_website/src/routes/+page.svelte.
If you don’t know Svelte and are using an LLM to code for you, remember to ask it to write in Svelte 5 syntax.
Static Files¶
All static files (e.g. logo.svg, favicon.svg, images, css files, etc.) should be put in the afterpython/static/ directory.
They will be automatically copied to the afterpython/_website/static/ directory during ap build.
Content-Type-Specific Static Files¶
In addition to the global afterpython/static/ directory, each content type can have its own static/ folder for content-specific assets:
afterpython/blog/static/- Static files specific to blog posts (e.g., thumbnail images, blog-specific graphics)afterpython/tutorial/static/- Static files specific to tutorialsafterpython/doc/static/- Static files specific to documentation
This organization helps keep content-related assets close to their source files. For example, if you have thumbnail images for your blog posts, place them in afterpython/blog/static/ rather than mixing them with global assets in afterpython/static/.
Content Type Configuration¶
Each content type (blog, tutorial, etc.) has a listing page that displays all posts of that type. You can customize these listing pages in afterpython.toml.
Default Thumbnails¶
Set a default thumbnail image for all posts within a content type:
[website.blog]
thumbnail = "blog_default_thumbnail.png"The thumbnail path is relative to the content type’s static folder. In this example, afterpython will look for afterpython/blog/static/blog_default_thumbnail.png.
This default thumbnail will be used for any blog post that doesn’t specify its own thumbnail.
Featured Post¶
Specify which post appears in the featured/hero section of the listing page:
[website.blog]
featured_post = "blog1.md"This will display blog1.md prominently in the hero section when users visit the blog listing page.
Example Configuration¶
Here’s a complete example for blog posts:
[website.blog]
thumbnail = "blog_default_thumbnail.png" # Default thumbnail for all blog posts
featured_post = "announcing-v1.md" # Featured post in hero sectionThe same configuration works for other content types:
[website.tutorial]
thumbnail = "tutorial_default_thumbnail.png"
featured_post = "getting-started.md"Built-in Features¶
Search¶
A search bar in the navigation lets users search across all of your content (docs, blog posts, tutorials, etc.) at once. Powered by PageFind — fully client-side, no server needed.
README.py¶
Drop a marimo notebook at afterpython/README.py to replace the markdown README.md rendering in the home page’s central section. AfterPython detects the file, exports it to HTML, and embeds it on the landing page.
Choose the export mode in afterpython.toml:
[website]
readme_py = "wasm" # or "static"
execute_readme_py = false # execute cells at build time and embed outputs as a preview (wasm mode only)wasm(default) — interactive. Cells run in the browser via Pyodide. Great for live demos of your package, but adds a ~10MB+ Pyodide download on first visit. Won’t work for packages with C extensions that aren’t ported to Pyodide.static— pre-rendered HTML, no runtime. Lighter, but cells can’t execute. AfterPython adds an “Open in molab” badge so users can still run the notebook on a real Python server hosted by marimo.
Set execute_readme_py = true to execute the notebook before exporting and embed the cell outputs as a preview — visitors see results immediately instead of a blank notebook while Pyodide boots. Marimo runs the execution in an isolated environment pinned to WASM-compatible packages when possible. Only honored in wasm mode.
README.md is still required (PyPI uses it for the long description) and is shown if README.py is absent or isn’t a marimo notebook.
FAQs¶
afterpython/faq.yml is rendered as the FAQs section on the project website. Each item needs a question and answer; category is optional.
- question: How do I install it?
answer: Run `pip install afterpython`, then `ap init`.
category: Getting Started
- question: Can I write content in Jupyter notebooks?
answer: |
Yes — `.ipynb` files in `afterpython/tutorials/` are auto-converted.
See the **[quickstart](/doc/quickstart)** for details.
category: Getting Started
- question: Is AfterPython free?
answer: Yes, it is free and open source.Both question and answer accept Markdown — inline code, links, lists, fenced code blocks, etc.
Categories are displayed in the order they first appear in faq.yml, so order your questions to control category order.
Announcement Banner¶
Set announcement under [website] in afterpython.toml to display a banner at the top of the home page on the project website. Markdown is supported (inline code, links, bold, emoji), so you can link to a release, blog post, or external page.
[website]
announcement = "🎉 v2.0 is out — [read the changelog](/blog/v2-release)"For longer messages, use a triple-quoted string. Keep it concise — the banner is meant for a one-glance heads-up, not a full announcement post. Leave it as "" to hide the banner.
API Reference¶
The API Reference section on the project website is generated by pdoc from your package’s docstrings, and lives at /api_reference/ on the deployed site.
By default, ap build does not generate the API Reference. This avoids breaking the build before your package is import-ready or has docstrings — pdoc errors are opt-in surface area.
To enable it, set the following in afterpython.toml:
[website]
api_reference = trueOnce enabled, every ap build will run pdoc against your package and the “API Reference” link will appear in the navbar automatically. The pages are also indexed by the site-wide search.
🚧 AI chatbot using WebLLM¶
🚧 Google Analytics¶
add google analytics support for the entire website
Compatibility¶
Currently afterpython only supports content built mystmd. It does NOT work with Sphinx, MkDocs etc.