- Multi-provider — query multiple lyrics sources with automatic fallback. LRCLIB included out of the box.
- Lyrics & metadata — retrieve track metadata by title, artist, ISRC, or URL, then fetch synced or plain lyrics.
- AI translation — translate lyrics into any language using OpenAI-compatible models.
- Pluggable caching — on-disk file cache or in-memory cache, with a
CacheAdapterinterface to bring your own. - Synced lyrics — query for timestamped lines and keep them through translation.
- TypeScript-first — fully typed with
.d.tsdeclarations included.
npm install lyrix-js
# or
pnpm add lyrix-js
# or
yarn add lyrix-jsimport { LyrixClient, lrclibProvider } from "lyrix-js";
const client = new LyrixClient({
providers: [lrclibProvider],
cache: true,
});
const { lyrics } = await client.getLyrics({
trackName: "Perfect",
artistName: "Ed Sheeran",
});
console.log(lyrics.join("\n"));Pass translateTo with an API config to get translated lines alongside the originals:
const result = await client.getLyrics(
{ trackName: "Usseewa", artistName: "Ado" },
{
translateTo: "English",
translation: {
apiKey: process.env.OPENAI_API_KEY,
model: "gpt-5.6-luna",
},
}
);
// Original
console.log(result.lyrics.join("\n"));
// Translated
console.log(result.translatedLyrics!.join("\n"));Translations are requested in small batches using strict structured output, which preserves the number and order of lyric lines. The service retries failed batches and keeps the original source lines if the translation provider remains unavailable.
const result = await client.getLyrics(
{ trackName: "Blinding Lights", artistName: "The Weeknd" },
{ sync: true }
);
for (const line of result.syncedLyrics!) {
console.log(`[${line.startTime}s] ${line.text}`);
}When synced lyrics are translated, timestamps are preserved on the translated lines as well (translatedSyncedLyrics).
new LyrixClient(config: LyrixClientConfig)| Option | Type | Description |
|---|---|---|
providers |
LyricsProvider[] |
Array of lyrics providers, queried in order. |
cache |
boolean | CacheAdapter |
true enables file caching in .lyrix-cache/. Pass a custom adapter for other storage. |
Returns Promise<LyricsResult>.
| Param | Type | Description |
|---|---|---|
track |
Track |
Query with trackName, artistName, isrc, and/or url. |
options |
LyricsOptions (optional) |
Sync mode, translation, and provider settings. |
Track
| Field | Type | Description |
|---|---|---|
trackName |
string |
Song title. |
artistName |
string |
Artist name. |
isrc |
string |
ISRC identifier. |
url |
string |
A MusicBrainz URL to resolve metadata from. |
LyricsOptions
| Field | Type | Description |
|---|---|---|
sync |
boolean |
Request timestamped (synced) lyrics. Default false. |
translateTo |
string |
Target language name or ISO code (e.g. "French", "ja"). |
translateFrom |
string |
Source language. Defaults to auto-detection. |
translation |
TranslationConfig |
API credentials — required when translateTo is set. |
TranslationConfig
| Field | Type | Description |
|---|---|---|
apiKey |
string |
OpenAI-compatible API key. |
model |
string |
Model ID (e.g. "gpt-4o"). |
baseUrl |
string |
Optional custom endpoint for proxies/alternate providers. |
LyricsResult
| Field | Type | Description |
|---|---|---|
track |
TrackMetadata |
Resolved metadata for the track. |
lyricsProvider |
string |
Name of the provider that returned lyrics. |
lyrics |
string[] |
Plain lyrics lines. |
synced |
boolean |
Whether these are synced lyrics. |
syncedLyrics |
LyricsLine[]? |
Timestamped lines (when sync: true). |
translatedLyrics |
string[]? |
Plain translated lines. |
translatedSyncedLyrics |
LyricsLine[]? |
Translated lines with original timestamps. |
LyricsLine
| Field | Type | Description |
|---|---|---|
text |
string |
Line text. |
startTime |
number? |
Timestamp in seconds. |
Implement CacheAdapter to store cached data anywhere:
interface CacheAdapter {
get(key: string): Promise<string | null>;
set(key: string, value: string): Promise<void>;
}Built-in adapters:
| Adapter | Storage | Constructor |
|---|---|---|
FileCacheAdapter |
Disk (.lyrix-cache/ by default) |
new FileCacheAdapter(path?) |
MemoryCacheAdapter |
In-memory Map |
new MemoryCacheAdapter() |
import { LyrixClient, MemoryCacheAdapter, lrclibProvider } from "lyrix-js";
const client = new LyrixClient({
providers: [lrclibProvider],
cache: new MemoryCacheAdapter(),
});Implement LyricsProvider to add your own source:
interface LyricsProvider {
name: string;
fetchLyrics(metadata: TrackMetadata, options?: LyricsOptions): Promise<LyricsResult | null>;
}const myProvider: LyricsProvider = {
name: "my-service",
async fetchLyrics(metadata, options) {
// fetch lyrics from your source
return {
track: metadata,
lyricsProvider: this.name,
lyrics: ["line 1", "line 2"],
};
},
};
const client = new LyrixClient({
providers: [myProvider, lrclibProvider],
});Providers are queried in order — the first to return a result wins.
| Error | When |
|---|---|
NoLyricsFoundError |
No provider returned lyrics for the given track. |
TranslationError |
translateTo was set but no translation config was provided, or the API call failed. |
When cache is enabled, metadata, lyrics, and translations are stored and reused:
- Metadata is keyed by track identifiers (ISRC, URL, or artist + title).
- Lyrics are keyed by track ID + provider name + sync mode.
- Translations are keyed by source lines + target language + model.
Versioned cache entries are invalidated when the internal schema changes, so bumping the library won't serve stale data.
git clone https://github.com/lyrixjs/lyrix-js.git
cd lyrix
pnpm install
pnpm build
pnpm test
pnpm lintMIT © 2026 Debangshu Das
