DEV Community

Unstable Entity
Unstable Entity

Posted on • Originally published at chordroom.com

How I Built a Free Chord & Lyrics Database with 260k+ Songs Using Node.js and PostgreSQL

I built ChordRoom — a free, open-source chord and lyrics database with over 260,000 songs. Here's the technical story of how it came together.

The Problem

As a guitarist, I was frustrated with existing chord sites. Most are:

  • Cluttered with ads (some have 5+ ad blocks per page)
  • Slow to load
  • Behind paywalls for basic features like transposing
  • Missing many songs, especially non-English ones

I wanted something clean, fast, and comprehensive.

The Stack

  • Backend: Node.js + Express with server-side rendering
  • Database: PostgreSQL (260k+ songs, 14k+ artists)
  • Frontend: Vanilla JS SPA with SSR for SEO
  • Hosting: Self-hosted on a Linux server with Apache reverse proxy

Key Technical Decisions

Server-Side Rendering for SEO

With 260k+ song pages, SEO is critical. I implemented hybrid SSR — the Express server generates full HTML with unique titles, meta descriptions, Open Graph tags, and JSON-LD structured data for each song page. When Google crawls /songs/12345, it gets:

<title>Stressed Out - Twenty One Pilots Chords & Lyrics</title>
<meta name="description" content="Stressed Out by Twenty One Pilots. Chords: Am, F, C, G...">
<script type="application/ld+json">{"@type": "MusicComposition", ...}</script>
Enter fullscreen mode Exit fullscreen mode

The SPA then hydrates on the client side for a smooth user experience.

Sitemap Strategy

Google limits sitemaps to 50,000 URLs per file. With 260k+ songs, I needed a sitemap index:

sitemap.xml (index)
├── sitemap-songs-0.xml (50k URLs)
├── sitemap-songs-1.xml (50k URLs)
├── ...
├── sitemap-artists.xml (14k URLs)
├── sitemap-genres.xml (921 URLs)
└── sitemap-languages.xml (60 URLs)
Enter fullscreen mode Exit fullscreen mode

Each sitemap is generated dynamically from the database with proper lastmod dates.

Internal Linking

Every song page links to:

  • The artist's page
  • Genre pages
  • 10 related songs by the same artist
  • Back to the homepage

This creates a web of internal links that helps search engines discover and index all 275k+ pages efficiently.

Browse Pages

Beyond individual songs, ChordRoom offers browse-by pages:

  • 14,283 artist pages — e.g., /artists/Ed-Sheeran
  • 921 genre pages — Rock, Pop, Jazz, Blues, and more
  • 60 language pages — English, Spanish, Portuguese, and beyond
  • 23 decade pages — From 1950s to 2020s
  • Easy songs for beginners — Curated /easy-songs page

What I Learned

  1. SSR is essential for content-heavy sites — Without it, search engines see an empty SPA shell
  2. Sitemap compliance matters — One giant sitemap file will be ignored; split into <50k URL files
  3. Internal linking is underrated — It's the single most impactful SEO technique for large sites
  4. Self-hosting works — For a content site, you don't need AWS. A Linux box with Apache does fine.

Try It Out

Check out ChordRoom — search for any song, browse by artist or genre, and let me know what you think!

It's completely free, no ads cluttering the interface, and works great on mobile. If you find it useful, there's a small support link in the footer.

The source code is on GitHub.


What chord sites do you use? Any features you'd love to see? Drop a comment below!

Top comments (0)