Skip to main content

html-minifier-terser vs htmlnano vs @aspect-build/minify-html: HTML Minification in Node.js (2026)

·PkgPulse Team

TL;DR

html-minifier-terser is the most popular HTML minifier — feature-rich, handles inline CSS/JS, highly configurable, maintained fork of html-minifier. htmlnano is the modular HTML minifier — PostCSS-style plugin architecture, integrates with PostHTML, safe defaults, used by Parcel. minify-html is the Rust-based HTML minifier — blazing fast native performance, WASM and Node.js bindings, aggressive minification. In 2026: html-minifier-terser for maximum configurability, htmlnano for PostHTML/Parcel integration, minify-html for maximum speed.

Key Takeaways

  • html-minifier-terser: ~10M weekly downloads — feature-rich, configurable, handles inline CSS/JS
  • htmlnano: ~2M weekly downloads — modular plugins, PostHTML ecosystem, used by Parcel
  • minify-html: ~500K weekly downloads — Rust/WASM, fastest performance, aggressive defaults
  • All three reduce HTML file sizes by removing whitespace, comments, and redundant attributes
  • html-minifier-terser is the most battle-tested and widely used
  • minify-html is 5-10x faster than JS-based minifiers

html-minifier-terser

html-minifier-terser — feature-rich HTML minifier:

Basic usage

import { minify } from "html-minifier-terser"

const html = `
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>PkgPulse</title>
    <style>
      body {
        margin: 0;
        padding: 0;
      }
    </style>
  </head>
  <body>
    <!-- Main content -->
    <div class="container">
      <h1>Compare npm packages</h1>
    </div>
    <script>
      console.log("Hello");
    </script>
  </body>
</html>
`

const minified = await minify(html, {
  collapseWhitespace: true,
  removeComments: true,
  minifyCSS: true,
  minifyJS: true,
  removeRedundantAttributes: true,
  removeEmptyAttributes: true,
  removeOptionalTags: true,
})

// → <!DOCTYPE html><html lang=en><meta charset=UTF-8><title>PkgPulse</title><style>body{margin:0;padding:0}</style><div class=container><h1>Compare npm packages</h1></div><script>console.log("Hello")</script>

Full configuration

import { minify } from "html-minifier-terser"

const result = await minify(html, {
  // Whitespace:
  collapseWhitespace: true,
  conservativeCollapse: false,    // Don't preserve single space
  collapseInlineTagWhitespace: false,

  // Comments:
  removeComments: true,
  removeCommentsFromCDATA: true,

  // Attributes:
  removeRedundantAttributes: true,  // Remove type="text" from input
  removeEmptyAttributes: true,      // Remove class=""
  removeOptionalTags: true,         // Remove optional closing tags
  removeAttributeQuotes: true,      // Remove quotes when safe
  collapseBooleanAttributes: true,  // disabled="disabled" → disabled
  sortAttributes: true,
  sortClassName: true,

  // Inline CSS/JS:
  minifyCSS: true,    // Uses clean-css
  minifyJS: true,     // Uses terser
  minifyURLs: true,

  // HTML5:
  html5: true,
  useShortDoctype: true,

  // Custom processing:
  processScripts: ["application/ld+json"],  // Minify JSON-LD
})

With build tools

// Webpack — html-webpack-plugin uses html-minifier-terser:
const HtmlWebpackPlugin = require("html-webpack-plugin")

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      template: "./src/index.html",
      minify: {
        collapseWhitespace: true,
        removeComments: true,
        minifyCSS: true,
        minifyJS: true,
      },
    }),
  ],
}

// Vite — vite-plugin-html:
import { createHtmlPlugin } from "vite-plugin-html"

export default {
  plugins: [
    createHtmlPlugin({
      minify: true,  // Uses html-minifier-terser internally
    }),
  ],
}

htmlnano

htmlnano — modular HTML minifier:

Basic usage

import htmlnano from "htmlnano"

const { html } = await htmlnano.process(`
  <div class="container">
    <!-- Comment -->
    <h1>Hello World</h1>
    <img src="photo.jpg" alt="" />
  </div>
`)

// → <div class="container"><h1>Hello World</h1><img src="photo.jpg" alt></div>

Preset configurations

import htmlnano from "htmlnano"

// Safe preset (default) — only safe transformations:
const safe = await htmlnano.process(html, {}, htmlnano.presets.safe)

// Aggressive preset — maximum minification:
const max = await htmlnano.process(html, {}, htmlnano.presets.max)

// Custom — cherry-pick modules:
const custom = await htmlnano.process(html, {
  removeComments: "safe",         // Remove non-conditional comments
  collapseWhitespace: "conservative",  // Safe whitespace collapse
  minifyCss: true,                // Minify inline CSS (uses cssnano)
  minifyJs: true,                 // Minify inline JS (uses terser)
  minifySvg: true,                // Minify inline SVGs (uses svgo)
  removeRedundantAttributes: true,
  collapseBooleanAttributes: true,
  removeEmptyAttributes: true,
  deduplicateAttributeValues: true,
  removeOptionalTags: false,      // Keep optional tags (safer)
})

With PostHTML

import posthtml from "posthtml"
import htmlnano from "htmlnano"

// Use as PostHTML plugin:
const result = await posthtml([
  // Other PostHTML plugins first:
  require("posthtml-expressions")({ locals: { title: "PkgPulse" } }),
  require("posthtml-include")(),

  // Then minify:
  htmlnano({
    removeComments: "safe",
    collapseWhitespace: "conservative",
    minifyCss: true,
  }),
]).process(html)

console.log(result.html)

With Parcel

// .htmlnanorc.js (Parcel uses htmlnano automatically):
module.exports = {
  removeComments: "safe",
  collapseWhitespace: "conservative",
  minifyCss: true,
  minifyJs: true,
  minifySvg: true,
  removeRedundantAttributes: true,
}

// Parcel applies htmlnano during production builds automatically

Available modules

htmlnano modules:

Whitespace:
  collapseWhitespace: "conservative" | "all" | false
  collapseAttributeWhitespace: true/false

Comments:
  removeComments: "safe" | "all" | false

Attributes:
  removeRedundantAttributes: true/false
  removeEmptyAttributes: true/false
  collapseBooleanAttributes: true/false
  deduplicateAttributeValues: true/false
  removeOptionalTags: true/false
  normalizeAttributeValues: true/false

Inline code:
  minifyCss: true/false (uses cssnano)
  minifyJs: true/false (uses terser)
  minifySvg: true/false (uses svgo)
  minifyJson: true/false

Other:
  mergeStyles: true/false
  mergeScripts: true/false
  sortAttributes: true/false
  sortAttributesWithLists: true/false
  removeUnusedCss: true/false (uses uncss)

minify-html

minify-html — Rust-based HTML minifier:

Node.js usage

import { minify } from "@nicolo-ribaudo/minify-html"

const html = Buffer.from(`
  <!DOCTYPE html>
  <html>
    <head>
      <title>PkgPulse</title>
    </head>
    <body>
      <!-- Comment -->
      <div class="container">
        <h1>Compare packages</h1>
      </div>
    </body>
  </html>
`)

const minified = minify(html, {
  do_not_minify_doctype: false,
  ensure_spec_compliant_unquoted_attribute_values: false,
  keep_closing_tags: false,
  keep_html_and_head_opening_tags: false,
  keep_spaces_between_attributes: false,
  keep_comments: false,
  minify_css: true,
  minify_js: true,
  remove_bangs: false,
  remove_processing_instructions: false,
})

console.log(minified.toString())
// → Very aggressively minified output

Configuration options

import { minify } from "@nicolo-ribaudo/minify-html"

const result = minify(htmlBuffer, {
  // Keep certain elements:
  keep_closing_tags: true,          // Preserve </p>, </li>, etc.
  keep_html_and_head_opening_tags: true,
  keep_comments: false,
  keep_spaces_between_attributes: false,

  // Inline minification:
  minify_css: true,     // Minify <style> and style attributes
  minify_js: true,      // Minify <script> content

  // Safety:
  do_not_minify_doctype: true,
  ensure_spec_compliant_unquoted_attribute_values: true,
})

Performance comparison

Benchmark: Minifying a 100KB HTML file (average of 100 runs)

html-minifier-terser:  45ms
htmlnano (safe):       38ms
htmlnano (max):        52ms
minify-html:            4ms  ← ~10x faster

For large-scale static sites (1000+ pages):
  html-minifier-terser:  ~45 seconds
  minify-html:           ~4 seconds

minify-html is written in Rust and compiled to native code,
making it significantly faster for batch processing.

Build tool integration

// Vite plugin:
import { minify } from "@nicolo-ribaudo/minify-html"
import { Plugin } from "vite"

function htmlMinifyPlugin(): Plugin {
  return {
    name: "html-minify",
    enforce: "post",
    apply: "build",
    transformIndexHtml(html) {
      return minify(Buffer.from(html), {
        minify_css: true,
        minify_js: true,
        keep_closing_tags: false,
      }).toString()
    },
  }
}

// vite.config.ts:
export default {
  plugins: [htmlMinifyPlugin()],
}

Feature Comparison

Featurehtml-minifier-terserhtmlnanominify-html
LanguageJavaScriptJavaScriptRust (WASM/native)
SpeedMediumMediumFast (10x)
ConfigurabilityHigh (30+ options)High (modular)Medium
Inline CSS minify✅ (clean-css)✅ (cssnano)✅ (built-in)
Inline JS minify✅ (terser)✅ (terser)✅ (built-in)
SVG minification✅ (svgo)
PostHTML integration
Plugin system
Used byWebpack, Vite pluginsParcelCustom builds
WASM supportN/AN/A
Weekly downloads~10M~2M~500K

When to Use Each

Use html-minifier-terser if:

  • Need the most battle-tested HTML minifier
  • Want fine-grained control over every optimization
  • Using Webpack or html-webpack-plugin
  • Need to minify inline CSS/JS with terser/clean-css

Use htmlnano if:

  • Using PostHTML for HTML processing
  • Using Parcel (built-in)
  • Want modular, plugin-based minification
  • Need SVG minification in inline SVGs

Use minify-html if:

  • Need maximum performance (large sites, many pages)
  • Building a static site generator or custom build tool
  • Want Rust-native speed for batch processing
  • Fine with fewer configuration options for faster output

Methodology

Download data from npm registry (weekly average, February 2026). Feature comparison based on html-minifier-terser v7.x, htmlnano v2.x, and @nicolo-ribaudo/minify-html v0.15.x.

Compare build tooling and performance utilities on PkgPulse →

Comments

Stay Updated

Get the latest package insights, npm trends, and tooling tips delivered to your inbox.