An ode to those who love the craft, an ode to the old internet, an ode to a time before numbers and figures dominated writing, an ode to a time where readers remembered their favourite writers, and an ode to the hope that all of it is still present, somewhere.
Ode is for writers who want to publish in an aesthetically pleasing website, who ignore the bells and whistles of the modern internet, and who want to create a better experience for their readers. It is opinionated, minimal, and easy to use, guided by its own ethos.
The theme/idea comes directly from journal.coffee which was my Wordpress-based website where I've written prose for years now. Its styling and design evolved with significant manual effort over the years. Wordpress was great but it became quite bloated over the years and I wanted a lightweight, faster place to write in. Plus, the reading mode and ease of markdown publishing has been on my mind for ages.
Rest assured, as of the very first release, I am using ode too!
[!WARNING]
Like all good things, Ode is currently changing and evolving. Things might break now and then.
You can find a live demo of the app here.
[!NOTE] For theme-specific screenshots, see THEMING.md



This is my favourite feature, personally.
https://github.com/user-attachments/assets/222af674-11f0-4b5a-8232-a31aca8a61b1
config.yamlconfig.yaml[!TIP] For detailed notes on how to setup a content repository with sync, look into the WRITING.md
If you want to self-host, use the public Docker image. Create a directory with your content:
my-site/
public/
config.yaml
content/
intro.md
pieces/
pages/
docker-compose.yml
Create a docker-compose.yml:
services:
ode:
image: ghcr.io/dimwitlabs/ode:latest
ports:
- "8080:4173"
restart: unless-stopped
volumes:
- /path/to/your/public:/app/public
[!TIP] Use an absolute path for the volume mount (e.g.,
/home/user/my-site/public). Relative paths may not work correctly with tools like Portainer.
Run:
docker compose up -d
Your site will be available at http://localhost:8080. Restart the container to rebuild after content changes:
docker compose restart
[!NOTE] In this case, you need to replace the content in
public/with your own.
Once you have your Fork or branch ready, you can deploy the app but the reader position Permalinks as well as the Body of Work links will fail. This is due to SPA handling of paths and (from my understanding) how React works. But this can be fixed.
You can directly to Vercel below. vercel.json already has the fixes Vercel will need.
https://github.com/DeepanshKhurana/ode/blob/46873b31df3d4b02bbb375d4389173a1b6ac3f6b/vercel.json#L1-L12
If you are like me, you probably have your own server where you will need to handle SPA routing. If you are using nginx, configuration templates are provided in the nginx/ directory.
If you are coming from WordPress, you can use the awesome lonekorean/wordpress-export-to-markdown to get your content in markdown format. It will mostly be plug and play with this version of Ode.
[!TIP] A longer guide is in WRITING.md
Create markdown files in public/content/pieces/ with front matter:
---
title: "Your Piece Title"
slug: "your-piece-slug"
date: 2025-11-23
categories:
- essays
- fiction
---
Write to your heart's desire.
Create markdown files in public/content/pages/ with front matter:
---
title: "About"
slug: "about"
date: 2021-06-14
---
Tell everyone everything!
[!NOTE] For complete theming documentation, including all available presets, customization options, and local font support, see THEMING.md
Ode comes with 10 built-in themes that you can use and customize. Switch between presets, override colors and fonts, or build your own theme from scratch.
Edit public/config.yaml to customize your site. You can handle quite a few things here:
https://github.com/DeepanshKhurana/ode/blob/fcc6d2b7b0b825e07cc07e94a43596e716dd8b79/public/config.yaml#L1-L49
npm install
npm run dev
Runs the app in development mode at http://localhost:5173
npm run build
This will:
1. Index all pieces from public/content/pieces/
2. Index all pages from public/content/pages/
3. Paginate pieces for reader mode
4. Calculate word/piece statistics
5. Generate RSS feed
6. Generate body of work archive
7. Build the production bundle
npm run preview
Run individual build scripts:
npm run build:pieces - Index piecesnpm run build:pages - Index pagesnpm run build:paginate - Paginate piecesnpm run build:stats - Calculate statisticsnpm run build:rss - Generate RSS feednpm run build:sitemap - Generate SitemapMIT
You are free to use this, break it, customise it. If you have any idea the community will benefit from, raise a PR or an Issue.