# assets-webpack-plugin: a JSON map of hashed asset paths for the rest of your stack

> assets-webpack-plugin is a small webpack plugin that writes a JSON file mapping each bundle name to the paths of the assets it produced, so a server side template or a Rails or ASP.NET Core view can reference the hashed filenames. It suits teams doing cache busting by content hash, and it sits at version 7 with a published release list that stopped in 2021.

**ztoben/assets-webpack-plugin** — Webpack plugin that emits a json file with assets paths

- Repository: https://github.com/ztoben/assets-webpack-plugin
- Website: https://www.npmjs.com/package/assets-webpack-plugin
- Stars: 950 · Forks: 103
- Language: JavaScript
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/ztoben-assets-webpack-plugin

## The problem is a template that does not know the hashed filename

Cache busting with webpack is easy and awkward at the same time. You put a hash in the output filename, the hash changes whenever the content changes, and suddenly every script tag in your HTML is wrong. The bundle is called main_2bb80372ebe8047a68d4.bundle.js and the template still says main.bundle.js.

assets-webpack-plugin solves exactly that problem, and nothing else. The README describes it as a plugin that emits a json file with assets paths, so that you can find them from somewhere else. The output is a JSON object keyed by bundle name, where each value maps an asset kind to a path.

```json
{
    "bundle_name": {
        "asset_kind": "/public/path/to/asset"
    }
}
```

The key is the name of the bundle, which is the key of the entry object in your webpack config, or main if your entry is an array. The inner key is the camel-cased file extension of the asset, so a .js file becomes js and a .css file becomes css.

That is a deliberately narrow contract. The plugin does not generate HTML, does not inline anything by default, and does not know about your template engine. It emits a file, and the rest of your stack reads it. For a Rails view, an ASP.NET Core layout, or a static site generator, that is exactly the seam you want, because the consumer of the manifest is code you control rather than a framework convention imposed on you.

## Version 6 and above requires webpack 5

The install section leads with a compatibility warning, and it is the first thing to sort out. Starting with version 6 the plugin works with webpack 5 and newer, and the README points users of an older webpack at the most recent 5.x.x release, which is 5.1.2.

```sh
npm install assets-webpack-plugin --save-dev
```

```sh
npm install assets-webpack-plugin@5.1.2 --save-dev
```

The peer dependency in the package metadata states webpack 5.0.0 or newer, which matches the README, and the plugin is installed as a dev dependency because it runs at build time and never ships in your application bundle.

The runtime requirements are modest. The engines field asks for node 10.x.x or newer, and the dependency list is short: camelcase, which is what produces the camel-cased asset kind keys, escape-string-regexp, and lodash. There is no native module and no build step for consumers, since the package ships a compiled dist directory and the main entry points at dist/index.js.

For context on the shape of the project, the source is small and conventional. The repository root has index.js, a lib directory, a test directory, a .babelrc, a .nvmrc, and the package.json, with the scripts for lint, test and build. The test script runs mocha over the test directory, the lint script runs standard through snazzy, and the build script compiles index.js and lib with babel into dist, with a prepublish hook that runs the build.

## The generated file is keyed by entry name and asset kind

It helps to see the whole shape at once, because the plugin is really just a transform over the stats webpack already knows.

Given an entry object with two bundles and an output filename that includes a hash, the emitted JSON looks like this.

```js
{
    entry: {
        one: ['src/one.js'],
        two: ['src/two.js']
    },
    output: {
        path: path.join(__dirname, "public", "js"),
        publicPath: "/js/",
        filename: '[name]_[hash].bundle.js'
    }
}
```

```json
{
    "one": {
        "js": "/js/one_2bb80372ebe8047a68d4.bundle.js"
    },
    "two": {
        "js": "/js/two_2bb80372ebe8047a68d4.bundle.js"
    }
}
```

Two properties of the output are worth pointing out. The values carry the publicPath from the webpack output configuration, so the paths in the manifest are the paths the browser will request, not the paths on disk. And the asset kind key is the extension rather than the full filename, which means a bundle that emits both a .js and a .css file produces two entries under the same bundle name.

The plugin instance itself is created with no arguments and added to the plugins array of the webpack configuration.

```js
var path = require('path')
var AssetsPlugin = require('assets-webpack-plugin')
var assetsPluginInstance = new AssetsPlugin()
```

The path option controls where the JSON file is written, and it defaults to the current directory, which the README notes will default to the highest level of the project unless useCompilerPath is specified.

## processOutput lets the manifest be a script instead of a file

The most useful option for anyone with a server rendered page is processOutput. It defaults to a JSON stringify function, and it formats the assets output, so you can replace the shape of the file entirely.

```js
new AssetsPlugin({
  processOutput: function (assets) {
    return 'window.staticMap = ' + JSON.stringify(assets)
  }
})
```

With that function in place, the output is a JavaScript assignment rather than a JSON document, and a page can include it with a plain script tag and read the map off window.staticMap. For a client side application that needs to know where its chunks live before the bundle loads, that removes a fetch and a parse step.

The metadata option is related in spirit but different in effect. It injects metadata into the output file, and all values are injected into the key named metadata.

```js
new AssetsPlugin({metadata: {version: 123}})
```

So a build number or a release identifier can travel inside the same file as the asset paths, which is handy when the consumer needs to know which build it is looking at.

Two smaller options round out the formatting side. prettyPrint is false by default and formats the JSON output for readability, which matters if a human is going to read the file during debugging. And manifestFirst, false by default, orders the assets output so the manifest is the first entry, which the README recommends for cases where script tags are generated from the assets json output and the order of import matters.

## includeManifest inlines the bootstrap for long-term caching

The includeManifest option is the one with a real architectural purpose behind it, and it is also the least obvious.

It inserts the manifest javascript as a text property in your assets, and it accepts the name or names of your manifest chunk. The README defines a manifest as the last CommonChunk that contains only the webpack bootstrap code, and the reason to inline it is production use when you want to inline the manifest in your HTML skeleton for long-term caching.

```js
new AssetsPlugin({includeManifest: 'manifest'})
```

The idea behind the caching strategy is the reason this option exists. If the bootstrap code is inlined into the HTML and the HTML is cached for a long time, then the rest of the application code can be split into chunks that are cached separately and invalidated by their own hashes. Inlining one small piece of bootstrap in the HTML breaks the dependency that would otherwise force the whole HTML to be regenerated whenever any chunk changes. The README links to a webpack issue and a blog post for the longer explanation of the pattern.

The option also accepts an array, so several manifests can be inlined at once.

```js
new AssetsPlugin({includeManifest: ['manifest1', 'manifest2']})
```

A related detail is fullPath, which is true by default and controls whether the output includes the full path of the generated file. Setting it to false gives you a bare bundle.js rather than a path. removeFullPathAutoPrefix, false by default, is the narrower version of that idea: when true, the full path is automatically stripped of the /auto/ prefix that webpack generates.

## update, path and the options the README only lists

Two options affect where the file goes and what happens to it across builds.

The path option sets where the JSON file is saved, and it defaults to the current directory, with the note that it will default to the highest level of the project unless useCompilerPath is specified. The useCompilerPath option overrides that and uses the compiler output path set in your webpack config.

```js
new AssetsPlugin({path: path.join(__dirname, 'app', 'views')})
```

```js
new AssetsPlugin({useCompilerPath: true})
```

The update option, false by default, changes the semantics from replace to merge. When set to true, the output JSON file will be updated instead of overwritten.

```js
new AssetsPlugin({update: true})
```

That distinction is worth a moment of thought, because it is where a surprising failure can hide. If two webpack configurations in a multi compiler build both write to the same file, or if a build writes a manifest and a later step is expected to add to it, then overwrite is wrong and update is right. The reverse also holds: with update enabled, a file that should have been replaced keeps entries from a previous build, and the manifest quietly describes an older build.

The README's table of contents lists a further set of options that are not described in the visible text: includeAllFileTypes, fileTypes, keepInMemory, integrity, entrypoints and includeFilesWithoutChunk. The option names suggest the direction, and the development dependencies in the package metadata include mini-css-extract-plugin and webpack-subresource-integrity alongside webpack 5.53.0, so the plugin is tested against the ecosystem those options reach into. The details of each should be read in the full README rather than inferred from the names.

There are also sections in the table of contents for using the plugin in multi compiler mode, with Rails, and with ASP.NET Core.

## A 7.x plugin whose published releases stopped in 2021

The maintenance picture is the part to weigh before you depend on this.

The published releases are 7.1.0 on 2021-04-23, 7.0.0 on 2020-12-11 and 6.1.2 on 2020-12-08. The package metadata in the repository declares version 7.1.1, so the working tree carries a patch bump on top of the newest release in the registry. The last push to the repository was on 2026-10-12 and the repository is not archived, so the code is being touched, but the npm release list has not moved in more than four years.

That gap is the thing to reason about. A webpack plugin does not usually need frequent releases, because it depends on webpack through a peer dependency and consumes a stable stats interface. The risk is not that the plugin breaks, it is that nobody has confirmed it still works against the webpack version you are on. The version 6 rewrite for webpack 5 support is evidence that breaking changes are handled by a major bump, and the README is explicit about the version boundary, which is a good sign, but a five year old release is not evidence of current compatibility with your toolchain.

The plugin's own development stack is dated in the same way. Babel 6 tooling, mocha 8, chai 4, standard 16 and rimraf 3 appear in the dev dependencies, and the CI configuration in the repository root consists of a Travis configuration and an AppVeyor configuration, both of which are services whose current status is not something this repository states. The renovate configuration in the root suggests dependency updates are automated, which helps the internal stack but does not produce a new npm release.

The licence is MIT, so there is no obstacle to vendoring the small source if it ever becomes necessary. The realistic read is that this is a well understood, narrowly scoped plugin with a small surface area, and the sensible response to an unmaintained release list is to test it against your webpack version once, pin that version, and keep the patch diff small.

## Conclusion

Adopt assets-webpack-plugin if you build with webpack 5, name your bundles with a content hash, and need a server side template or view to know the final filenames. Do not adopt it if your pipeline already tracks assets through a plugin, if you are still on webpack 4, or if you need the manifest to be authoritative across several builds, since the update option merges rather than replaces. Verify first that your webpack version satisfies the peer dependency of 5.0.0 or newer, that the JSON file lands where your template reads it, and that the path values carry the publicPath prefix your application actually serves, before you remove the hard coded script tags.

## FAQ

### What does assets-webpack-plugin do?

It is a webpack plugin that emits a json file with the paths of the generated assets, keyed by bundle name and by camel-cased asset kind. The README gives the motivation as the need to find the generated bundles from somewhere else when filenames contain a hash for cache busting.

### Which webpack versions does assets-webpack-plugin support?

Starting with version 6 the plugin works with webpack 5 and newer, and the peer dependency in the package metadata states webpack 5.0.0 or newer. The README points users of older webpack at the most recent 5.x.x release, which is 5.1.2.

### How do I install assets-webpack-plugin and where does the JSON file go?

Install it as a dev dependency with npm install assets-webpack-plugin --save-dev. The JSON file is named webpack-assets.json by default and is written to the current directory, which the README says defaults to the highest level of the project unless useCompilerPath is set.

### What can the includeManifest option do?

It inserts the manifest javascript as a text property in your assets, accepting the name or names of your manifest chunk. The README explains that this is useful in production when you want to inline the manifest in your HTML skeleton for long-term caching.

### How do I change the shape of the generated file?

Use processOutput, which by default is a JSON stringify function, and return your own string from it. The README gives an example that returns window.staticMap = followed by a JSON stringify of the assets, and the metadata option injects values under a metadata key.

### Is assets-webpack-plugin still maintained?

The repository is not archived and the last push was on 2026-10-12, but the published npm releases stop at 7.1.0 on 2021-04-23 while the repository declares 7.1.1. The licence is MIT, and there is no newer release to test against.

## Sources

- [License: MIT](https://github.com/ztoben/assets-webpack-plugin/blob/master/LICENSE)
- [Project website](https://www.npmjs.com/package/assets-webpack-plugin)
- [README](https://github.com/ztoben/assets-webpack-plugin/blob/master/README.md)
- [Releases](https://github.com/ztoben/assets-webpack-plugin/releases)
- [ztoben/assets-webpack-plugin on GitHub](https://github.com/ztoben/assets-webpack-plugin)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/ztoben-assets-webpack-plugin
