npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

changelog-parser

v4.1.0

Published

Change log parser for node.

Downloads

129,405

Readme

changelog-parser

Change log parser for node.

npm build downloads

Features

  • Parses a CHANGELOG.md file (or raw text string) into a structured object: a title, an optional description, and an array of version entries.
  • Extracts each version's number, date, body, and list items, grouped by ### subheading.
  • Promise-based, with a legacy Node-style callback also supported.
  • Optionally strips markdown from parsed entries.

Supported formats

These common changelog formats are officially supported:

  • Keep a Changelog: ## [x.y.z] - YYYY-MM-DD headings, ### Added / ### Changed / etc. sections
  • Conventional Changelog: ## [x.y.z](compare) (date) headings, with or without top-level title
  • Release Please: ## [x.y.z](compare) (date) headings with ### ⚠ BREAKING CHANGES section
  • Standard Version: headings set by release type (# major, ## minor, ### patch)
  • auto-changelog: #### [vx.y.z](compare) headings with the date on a > ... blockquote line

Maintained with 100% test coverage, verified on Linux, macOS, and Windows across all supported Node.js versions.

Install

npm install changelog-parser

Usage

This module is ESM-only. It exports a named parseChangelog function that parses a changelog and returns a Promise.

import { parseChangelog } from 'changelog-parser'

// async / await
const changelog = await parseChangelog('path/to/CHANGELOG.md')

// or as a promise
parseChangelog('path/to/CHANGELOG.md')
  .then((changelog) => console.log(changelog))
  .catch((err) => console.error(err))

A default export of the same function is also available (import parseChangelog from 'changelog-parser').

CommonJS consumers on Node.js >= 22.12 can still require() it, but the function is no longer the module itself:

const { parseChangelog } = require('changelog-parser')

Callback

A Node-style callback is also supported. It was the original interface (the package predates native promises) and is kept for backwards compatibility. New code should use the returned promise.

parseChangelog('path/to/CHANGELOG.md', (err, result) => {
  if (err) throw err

  console.log(result)
})

Options

The first argument can be a path string or an options object (string | ChangelogOptions). You must provide either filePath or text.

interface ChangelogOptions {
  /** Path to a changelog file. */
  filePath?: string
  /** Raw changelog text (alternative to `filePath`). */
  text?: string
  /** Strip markdown from parsed entries. Defaults to `true`. */
  removeMarkdown?: boolean
}

Command-line interface

There is also a command-line interface available.

npx changelog-parser <path-to-changelog.md> # invoke with npx
npm install -g changelog-parser # or install globally

This installs a program called changelog-parser that you simply pass a CHANGELOG.md file.

changelog-parser path/to/CHANGELOG.md

This will print the JSON object representing the change log to the terminal.

Alternately you can run it without arguments and it will look for a CHANGELOG.md file in the working directory.

Migrating from 3.x

As of v4.0.0 this package is ESM-only. The API and output are otherwise unchanged.

  • ESM: import parseChangelog from 'changelog-parser', or the named import { parseChangelog }.
  • CommonJS: a bare require('changelog-parser') no longer returns the function. On Node 22.12+, where require() of an ES module is supported, use const { parseChangelog } = require('changelog-parser'). On older Node, use a dynamic import(). Node 22.12+ is only needed for this path.
  • body and description are now always joined with \n rather than the OS line ending, so output no longer varies by platform.

Output

parseChangelog resolves to (and the callback receives) a Changelog. These types are exported.

interface Changelog {
  /** The document title (the first `#` heading that is not itself a version), if present. */
  title?: string
  /** Free text between the title and the first version, if any. */
  description?: string
  /** Version entries, in document order. */
  versions: ChangelogVersion[]
}

interface ChangelogVersion {
  /** Semver string if the heading is semver-compliant, otherwise `null`. */
  version: string | null
  /** The raw heading text. */
  title: string | null
  /** Date parsed from the heading if present, otherwise `null`. */
  date: string | null
  /** All content under the heading, as a single string. */
  body: string
  /**
   * List items grouped by subheading. The `_` key holds every list item;
   * each `### Subheading` adds a key with the items beneath it.
   */
  parsed: Record<string, string[]>
}

For example, this changelog:

# Changelog

## [1.1.0] - 2024-03-15

### Added

* A `format` option.

### Fixed

* Squashed a bug.

## [1.0.0] - 2024-01-01

* First release.

parses to:

{
  title: 'Changelog',
  versions: [
    {
      version: '1.1.0',
      title: '[1.1.0] - 2024-03-15',
      date: '2024-03-15',
      body: '### Added\n\n* A `format` option.\n\n### Fixed\n\n* Squashed a bug.',
      parsed: {
        _: ['A format option.', 'Squashed a bug.'],
        Added: ['A format option.'],
        Fixed: ['Squashed a bug.']
      }
    },
    {
      version: '1.0.0',
      title: '[1.0.0] - 2024-01-01',
      date: '2024-01-01',
      body: '* First release.',
      parsed: { _: ['First release.'] }
    }
  ]
}

A version heading can be at any level (# through ######). A # or ## is always a version, except a # that is the document title (the first # heading that is not itself a version). At ### and deeper, a heading is a version only when it looks like one, so conventional-changelog / standard-version patch headings (###) and auto-changelog version headings (####) are captured, while a ### Section such as ### Added is not.

The version number is read whether the heading is bare (2.1.0), v-prefixed (v1.0.0), or wrapped in brackets and optionally linked ([0.9.0](...)). It is null when the heading is not semver-compliant (such as Unreleased). Dates are recognized in common numeric formats (YYYY-MM-DD, DD.MM.YYYY, parenthesized (YYYY-MM-DD)) and textual English formats (20 January 2021, January 20, 2021). The date is taken from the heading, or from a > blockquote line directly beneath it when the heading carries none (as auto-changelog writes them).

parsed is flat: it captures one entry per top-level list item. Nested or indented sub-items are not split into their own entries, but the full original text (including any nesting) is always available in body.

Contributing

Contributions welcome! Please read the contributing guidelines first.

License

ISC

Log image is from emojipedia.