mrkeyoor.com_
Tue 22 Sept 18:50 UTC
npmUtilsupdated 22 Sept 2026

mammoth review

Mammoth 1.12.1 turns DOCX structure into an HTML fragment or plain text. It maps Word paragraph and run styles to headings, lists, links, tables, notes, images, and project-defined elements, while deliberately ignoring much of Word's page styling. The current patch blocks a Windows CLI image-output path escape involving backslashes in a crafted content type and avoids self-referencing numbering styles. Our test found a 128.3 KB gzipped browser import and no bundled TypeScript declarations, so this is a document converter rather than a tiny frontend helper.

Verdict

Our Mammoth 1.12.1 install took 1.8 seconds, occupied 10 MB across 27 packages, and generated a 128.3 KB gzipped browser import with no audit findings. Choose it for style-led Word publishing, then budget for sanitization, image storage, and warning review.

We installed it

Lab card: what happened when we installed mammothScreenshot of mammoth documentation
Install✓ · 1.8s27 packages on disk · 10 MB
ImportESM import works · require() works · CommonJS package
Browser128.3 KBgzipped (504 KB minified), bundled with esbuild
Typesno TypeScript types found
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does mammoth install cleanly?

Yes. In a fresh container with an empty cache, npm install mammoth finished in 2 seconds, leaving 27 packages and 10 MB on disk. npm audit reported no known vulnerabilities.

How much does mammoth add to a browser bundle?

128.3 KB gzipped (504 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does mammoth work with both ESM and CommonJS?

Yes. Both import 'mammoth' and require('mammoth') worked in Node 22 in our run. The package is published as CommonJS.

Does mammoth include TypeScript types?

No type declarations were found in our install, so TypeScript users need their own declarations.

mammoth or docx-preview: which should you use?

docx-preview: Use it when browser output should retain more of the original Word page appearance. Our Mammoth 1.12.1 install took 1.8 seconds, occupied 10 MB across 27 packages, and generated a 128.3 KB gzipped browser import with no audit findings.

When should you not use mammoth?

The HTML must visually reproduce Word pages; Mammoth ignores table borders and does not preserve exact pagination, columns, or floating placement

API stability4/5The 1.x public surface still centers on convertToHtml(), extractRawText(), Node and browser input objects, result messages, style maps, and image converters. Version 1.12.1 fixes parser and CLI behavior without replacing those entry points. Two documented edges reduce the score: convertToMarkdown() is deprecated, and transformDocument is described as unstable. New application code should keep both outside its core conversion contract.
Docs4/5The repository README returns HTTP 200 and documents CLI use, runtime-specific inputs, style-map syntax, embedded mappings, image callbacks, messages, comments, notes, bookmarks, raw text, transforms, and security. It plainly states that Mammoth does not sanitize source documents and explains why external file access defaults off. The information is concentrated in one long page, and the measured package has no TypeScript declarations to supply editor-level API guidance.
Maintenance4/5npm published 1.12.1 on August 9, 2026, and GitHub records the latest push on the same date. The repository is unarchived, has 6,287 stars, and reports 64 open issues and pull requests combined. The patch closed a Windows output-directory traversal route and a recursive numbering edge, while 1.12.0 expanded hyperlink parsing. Current release details live in NEWS and npm rather than the stale GitHub latest-release endpoint.
Ecosystem4/5The npm endpoint counted 7,564,202 downloads from August 18 through August 24, 2026. Mammoth runs in Node and browsers, accepts the normal in-memory file shapes for each, and exposes hooks for image storage and style policy. Our browser build was 504 KB minified and 128.3 KB gzipped, while installation produced 27 packages. That cost is defensible on a dedicated import route, but wasteful in a general application bundle.

Use it if

  • Editors use named Word styles and the publishing system wants semantic HTML controlled by site CSS
  • A Node service must accept file paths or Buffers while a browser workflow accepts ArrayBuffer input through the same converter
  • Conversion warnings can be reviewed and custom image handling can place extracted assets in controlled storage
  • Headings, lists, links, tables, notes, and inline formatting matter more than matching Word pagination and positioning
Skip it if

Setup reality

We installed Mammoth 1.12.1 in a fresh Node 22 Bookworm sandbox in 1.8 seconds. npm left 27 packages using 10 MB and reported zero known vulnerabilities. Mammoth declares 10 direct dependencies, no peer dependencies, and 2,508 KB unpacked. It uses the BSD-2-Clause license and requires Node 12 or newer. CommonJS require() and ESM import both worked. We found no TypeScript declarations. An esbuild browser import measured 504 KB minified and 128.3 KB gzipped.

Node input is either { path } or { buffer }; browser input is { arrayBuffer }. convertToHtml() resolves with value and messages, and warnings can accompany usable HTML. Store those messages and decide which ones block publication. Named Word styles give the most repeatable output, while direct font and spacing choices often do not. User style maps override defaults. For uploaded files, set includeEmbeddedStyleMap: false when a document must not inject its own mapping rules.

Images default to data URLs inside the HTML. That inflates stored markup and bypasses normal asset checks. A convertImage handler can read bytes, enforce size and content-type rules, store the file, and return a URL. Browser code should use readAsArrayBuffer() or readAsBase64String(); readAsBuffer() needs a Buffer polyfill there. Version 1.12.1 matters on Windows because it stops a crafted image subtype from escaping the CLI output directory through a backslash path.

Mammoth does not sanitize its result, so apply an allowlist before placing output in a page. Leave externalFileAccess disabled for uploads, cap input size, and isolate conversion with time and memory limits. Give each result an idPrefix when several documents share a page, or footnote and bookmark IDs can collide. If layout fidelity is the requirement, a DOCX renderer or office conversion service is a better starting point than a growing pile of style-map exceptions.

Patterns

Convert one DOCX file in Node convert-file-to-html

const mammoth = require('mammoth')

const result = await mammoth.convertToHtml({ path: './article.docx' })
console.log(result.value)
for (const message of result.messages) console.warn(message.type, message.message)

Promise resolution does not mean a clean conversion; inspect every warning in result.messages before publication.

Convert an uploaded Buffer safely convert-buffer-to-html

const result = await mammoth.convertToHtml(
  { buffer: uploadedFile.buffer },
  { idPrefix: `doc-${documentId}-` },
)
const safeHtml = sanitize(result.value)

Mammoth returns unsanitized HTML, so the sanitizer must run before the fragment reaches any rendering path.

Convert a browser File on demand convert-in-browser

const arrayBuffer = await file.arrayBuffer()
const { value, messages } = await mammoth.convertToHtml({ arrayBuffer })
preview.innerHTML = sanitize(value)
console.table(messages)

Our full browser import measured 128.3 KB gzipped; lazy-load it on the route that accepts DOCX files.

Extract paragraphs as plain text extract-plain-text

const { value, messages } = await mammoth.extractRawText({ path: './notes.docx' })
const paragraphs = value.split(/\n\n+/).filter(Boolean)

extractRawText() removes formatting and separates source paragraphs with two newline characters.

Map named editorial styles map-word-styles

const styleMap = [
  "p[style-name='Article Title'] => h1:fresh",
  "p[style-name='Standfirst'] => p.standfirst:fresh",
  "p[style-name='Code Block'] => pre:fresh",
]
const result = await mammoth.convertToHtml({ path: './article.docx' }, { styleMap })

Named paragraph styles survive authoring more predictably than direct font-size or spacing choices.

Disable every inherited style map disable-default-maps

const result = await mammoth.convertToHtml(input, {
  styleMap: projectStyleMap,
  includeDefaultStyleMap: false,
  includeEmbeddedStyleMap: false,
})

With both mapping sources off, the project style map must describe every source style the publisher accepts.

Store extracted images outside HTML store-images-separately

const convertImage = mammoth.images.imgElement(async (image) => {
  const bytes = await image.readAsBuffer()
  const url = await imageStore.put(bytes, image.contentType)
  return { src: url, alt: image.altText || '' }
})
const result = await mammoth.convertToHtml(input, { convertImage })

Validate byte length and content type before storage; readAsBuffer() is Node-specific unless the browser supplies Buffer.

Retain empty source paragraphs keep-empty-paragraphs

const result = await mammoth.convertToHtml(input, {
  ignoreEmptyParagraphs: false,
})

The default drops empty paragraphs; keeping them can preserve intentional blanks or import layout noise better handled by CSS.

Include Word comments include-comments

const result = await mammoth.convertToHtml(input, {
  styleMap: [
    'comment-reference => sup.comment-ref',
    'comment => aside.comment:fresh',
  ],
})

Comments are omitted unless mapped, and their text and links need the same sanitization policy as body content.

Embed a mapping in the DOCX embed-style-map

const mapped = await mammoth.embedStyleMap(
  { path: './source.docx' },
  "p[style-name='Article Title'] => h1:fresh",
)
await fs.promises.writeFile('./mapped.docx', mapped.toBuffer())

Future conversions read the embedded map unless includeEmbeddedStyleMap is set to false.

Reject selected conversion warnings fail-on-warnings

const result = await mammoth.convertToHtml(input, options)
const warnings = result.messages.filter((message) => message.type === 'warning')
if (warnings.length) {
  throw new Error(warnings.map((message) => message.message).join('; '))
}
return sanitize(result.value)

Test real editor documents before making all warnings fatal, since some describe acceptable loss of unsupported formatting.

Run the patched CLI conversion convert-with-cli

npx mammoth ./article.docx ./article.html --output-dir=./article-assets --style-map=./styles.map

Use 1.12.1 or newer on Windows because the patch blocks a crafted image subtype from escaping the output directory.

Alternatives

PackageRegistryPick it when
docx-previewnpmUse it when browser output should retain more of the original Word page appearance
officeparsernpmUse it for text extraction across office formats and PDF instead of semantic DOCX-to-HTML conversion
word-extractornpmUse it when plain text from both old DOC and DOCX files is the actual requirement

More utils guides

lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.