Bhaktamar.org — five thousand pages, no database.
A Jain devotional library: three thousand hymns, verses and texts digitised from printed books, given a search that understands Devanagari and romanised Hindi alike, and shipped as flat files that need nothing running behind them.

- Domain
- Jain devotional content
- Scale
- 5,250 pages, statically built
- Core build
- Next.js · static export
- Status
- Live at bhaktamar.org
The texts existed. Finding one didn't.
The material was never the problem. Jain devotional literature — hymns, verses, commentaries, ritual texts — exists in abundance, in print and in PDFs passed between families. What didn't exist was a way to find a specific line without already knowing which book it was in.
The audience makes that harder, not easier. Readers are mobile-first and skew older, often reading Devanagari at increased zoom on a mid-range Android phone. Many will search by typing a half-remembered line in Roman letters, because switching keyboards is friction.
So the work split in two: turn printed books into structured, validated records — and then build a search that meets people where they actually type.
The constraint that shaped everything: no database, no backend, no analytics. Every page is a file on disk, so the archive stays cheap to host and hard to break.
Thirty-eight books, three thousand records.
The bulk of the work was not code. It was turning printed and scanned sources into consistent, machine-readable records that a site could be built from.
Where the thinking went.
Search that reads how people type
Queries match across Devanagari, IAST transliteration and loose romanised Hindi, with vowels folded so several spellings all reach the same verse. It also searches by composer and by tune.
A two-tier index, not one big blob
Titles load when the search overlay opens; the full body text is split into shards fetched only when a title search finds nothing. A phone doesn't download the whole corpus to look up one line.
Astronomy computed at build time
Choghadiya, panchang and vow timings are calculated per city from ephemeris data — with the day rolling over at sunrise, not midnight, and each city's own timezone applied.
Correctness enforced by CI
Seven build gates fail the deploy outright — duplicate titles, orphaned pages more than three clicks from home, missing metadata, oversized JavaScript, untransliterated entries, malformed sitemaps.
A test that guards the ethics
Devotional text can drift into promising outcomes. A build test reads the content and fails the deploy on any language claiming a cure or guaranteeing a result. Traditional belief is labelled as exactly that.
Duplicate content, measured and fixed
Two locales meant two URLs competing for one query — over three thousand page pairs sharing a title. Pages now self-assess whether their translation is real, and only surface when it is.
A new domain only gets one first impression.
The site was finished and deployed before it was ever submitted to a search engine. That was deliberate. A fresh domain's first crawl sets a quality baseline that is slow and expensive to move afterwards — so the fixing happened first, not after the traffic disappointed.
That sprint found real problems. Nine section pages were throwing a client-side exception in production, traced to structured data large enough to desynchronise the page's own streaming parser. Romanised search had been silently dead across the entire corpus because of a misplaced character in a build script. The whole content library was leaking into the browser bundle and pushing the build to twelve gigabytes of memory.
None of those would have shown up in a page that merely looked correct. They surfaced because the build was made to check itself.
Honest status: the site is live and the content is complete in Hindi. Recorded audio and a full English translation are the next milestones, not shipped features.
What it's built on
Site
- Next.js App Router
- Static export — no server
- React · TypeScript
- Tailwind CSS, themed by tokens
- Self-hosted Devanagari webfonts
- Light / dark, set before paint
Content & Data
- Structured JSON, read at build
- Schema validation on every record
- Transliteration generated, not typed
- Swiss Ephemeris astronomy
- Build-time OG image generation
- Cloudflare R2 for media
Delivery
- GitHub Actions, nightly rebuild
- Seven blocking quality gates
- Transport derived from config
- Dry-run mode before any upload
- Shared hosting behind Apache
- No analytics, no third-party scripts
Sitting on an archive nobody can search?
Books, records, catalogues, back-issues — the work is turning them into structure, then making that structure findable.