---
title: Migrating TDS from Docsify to Hugo
date: '2026-02-07T12:01:10+08:00'
categories:
- llms
- coding
- education
description: AI-assisted migration makes it feasible for non-experts to move course sites across stacks quickly, reducing dependence on LMSs and specialized coding knowledge.
keywords: [Docsify, Hugo, migration, Codex, education technology, static sites]
---
This morning, I migrated my [Tools in Data Science course page](https://tds.s-anand.net/) from [Docsify](https://docsify.js.org/) to [Hugo](https://gohugo.io/) using [Codex](https://openai.com/codex/).
**Why?** Because Docsify was great for a single term. For multiple terms, archives became complex. I _still could_ have made it work, but it felt like time to move towards a static site generator.
I don't know how [Hugo](https://gohugo.io/) or [Go](https://golang.org/) work. I didn't look at the code. I just gave Codex instructions and it did the rest.
This gives me a bit more confidence that educators can start creating their own course sites without needing coding or platforms. Soon, they might not be stuck to [LMS](https://en.wikipedia.org/wiki/Learning_management_system)s either - they can build their own.
Here are the prompts I used, along with Codex's responses, leading to two commits:
- [Migrate from Docsify to Hugo deployment](https://github.com/sanand0/tools-in-data-science-public/commit/8587bdcf8afbbc5f6b2fbae94921e043bcc62ed8)
- [feat(site): dynamic course detection and improved sidebar navigation](https://github.com/sanand0/tools-in-data-science-public/commit/168f69827c121307c9b1186afc7c2f0b9b71fa7f)
---
### Prompt 1
Generate a MIGRATION-PLAN.md for migrating this student course site from docsify to Hugo.
Currenty, this site uses docsify to render Markdown as HTML on the fly.
Create a setup.sh that generates a static version of the site under public/ using Hugo.
Use a popular, elegant, minimal Hugo theme of your choice. We want to retain the sidebar navigation, as well as the archives under 2025-01/, 2025-05/, 2025-09/, and more in the future.
Minimize the custom coding needed to achieve this.
Agent response
I’ll inspect the repository structure to map the current Docsify content layout, then I’ll create `MIGRATION-PLAN.md` and a `setup.sh` that builds a Hugo static site into `public/` with minimal custom logic and preserved sidebar/archive organization.
I found the Docsify setup and the key files (`index.html`, root `_sidebar.md`, plus archive subfolders with their own `_sidebar.md`/`README.md`). Next I’ll inspect those files and then draft a migration plan plus an idempotent `setup.sh` that maps this structure into Hugo with minimal custom templates.
I have enough context to implement this cleanly. I’m now choosing a Hugo docs theme and validating its sidebar configuration model so `setup.sh` can auto-generate navigation from your existing `_sidebar.md` files with minimal maintenance for future archive terms.
I validated `hugo-book` and will use it because it gives a built-in left docs sidebar with minimal configuration. I’ll now implement `setup.sh` to generate a Hugo workspace from your existing markdown tree and build to `public/`, then add `MIGRATION-PLAN.md` describing the migration steps and rationale.
I’m about to add two files: `setup.sh` (idempotent Hugo build pipeline into `public/`) and `MIGRATION-PLAN.md` (phased migration plan, structure mapping, and rollout checks). I’ll keep the approach low-code by relying on Hugo Book’s built-in sidebar behavior and automatic archive folder discovery.
I’ve written both files and will quickly sanity-check them (including a dry run of `setup.sh` in this environment, which should currently fail early because `hugo` isn’t installed here).
I found one cleanup point: `setup.sh` checked for `rsync` even though it doesn’t use it. I’ll remove that extra dependency and then provide a concise summary of what was added.
Created both requested files:
1. `MIGRATION-PLAN.md`
2. `setup.sh`
What I implemented:
- Chose `hugo-book` as the theme (popular, minimal, docs-style sidebar).
- `setup.sh` now:
- Creates an isolated Hugo workspace at `.hugo-build/site`
- Clones `hugo-book`
- Generates `hugo.toml`
- Copies tracked markdown into Hugo `content/`
- Converts every `README.md` to `_index.md` (so `/`, `/2025-01/`, `/2025-05/`, `/2025-09/` keep clean section URLs)
- Skips Docsify-only `_sidebar.md`
- Copies all tracked non-markdown files into Hugo `static/`
- Builds static output into `public/`
Notes:
- I could not run a full build here because `hugo` is not installed in this environment (`Error: missing required command 'hugo'`).
- Once Hugo Extended is installed, run:
```bash
./setup.sh
```
Files:
- `setup.sh`
- `MIGRATION-PLAN.md`
---
### Prompt 2
Use `mise x hugo -- hugo` and run and test it.
Agent response
I’ll run `setup.sh` through `mise x hugo --` so Hugo is available in PATH for the script, then verify the generated `public/` output and key archive routes.
The first run failed because `mise` couldn’t write under `~/.cache/mise` in this sandbox. I’ll rerun using a temporary cache directory and then validate the generated site.
`mise x hugo -- hugo` is installing the standard Hugo binary (not Extended), so the script’s Extended check fails. I’ll quickly check the available `mise` variants and use an Extended one to complete the test run.
`mise` does not expose an “extended” Hugo variant here. I’ll make `setup.sh` tolerant of standard Hugo (warn instead of hard-fail), then run it with `mise x hugo --` and verify whether the build succeeds end-to-end.
The build failed exactly at SCSS compilation, so we do need Hugo Extended for `hugo-book`. I’m testing `mise x hugo@extended -- hugo` with temporary mise data/cache dirs to keep everything inside writable paths.
Found the issue: with `mise`, Extended is a separate tool named `hugo-extended` (not a variant of `hugo`). I’ll run using that to complete the test build.
Build now succeeds with Hugo Extended. I’m validating the generated `public/` output, including root and archive routes plus sidebar links.
Ran and tested.
Results:
1. `mise x hugo -- hugo version`
- Output: `hugo v0.153.3 ...` (non-extended)
2. `mise x hugo -- ./setup.sh`
- Fails at SCSS compile (`TOCSS ... you need the extended version`) because `hugo-book` requires Hugo Extended.
3. `mise x hugo-extended -- hugo version`
- Output: `hugo v0.155.2+extended ...`
4. `mise x hugo-extended -- ./setup.sh`
- Succeeds.
- Generated site at `public/`
- Build summary: `Pages 289`, `Static files 103`, total ~1.6s.
Validation checks passed:
- `public/index.html` exists
- `public/2025-01/index.html` exists
- `public/2025-05/index.html` exists
- `public/2025-09/index.html` exists
- Sidebar contains links for archive terms and pages like `marks-dashboard` and `system-requirements`.
I also adjusted `setup.sh` so non-extended Hugo emits a warning instead of exiting immediately (`setup.sh`). The actual build still correctly fails later if the active theme needs Extended.
---
### Prompt 3
The sidebar for the home page should only contain the contains of \_sidebar.md.
The sidebar for 2025-01/, 2025-05/, and 2025-09/ should only contain the contents of the respective folders' \_sidebar.md.
Convert any links to images/ to an absolute link starting with /images/.
Re-run.
Agent response
I’ll update `setup.sh` to generate section-specific sidebars directly from each `_sidebar.md` (root and archive folders), override Hugo Book’s menu partial to use those sidebars, rewrite `images/` links to `/images/`, then rebuild and verify the output.
I’m editing `setup.sh` now to: 1) normalize `_sidebar.md` into per-section sidebar files, 2) override Hugo Book’s menu partial to render only the correct sidebar by section, and 3) rewrite markdown links from `images/` or `../images/` to `/images/`. Then I’ll rebuild and verify.
Implemented and re-ran with your requirements.
Changes made in `setup.sh`:
- Sidebar behavior:
- Added per-section sidebar generation from source `_sidebar.md` files:
- root: `_sidebar.md`
- `2025-01/`: `2025-01/_sidebar.md`
- `2025-05/`: `2025-05/_sidebar.md`
- `2025-09/`: `2025-09/_sidebar.md`
- Added a Hugo Book partial override at `.hugo-build/site/layouts/_partials/docs/menu-filetree.html` during build so:
- home and non-archive pages use only root `_sidebar.md`
- pages under `/2025-01/`, `/2025-05/`, `/2025-09/` use only their own folder sidebar
- Link normalization in sidebars:
- Converts `.md` links to Hugo-style paths (e.g. `/foo/`)
- Normalizes sidebar-local links like `http-requests` to `/http-requests/`
- Removes docsify inline `