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

strapi-plugin-data-excel-exporter

v1.1.1

Published

Export Strapi v5 collections to xlsx files from the admin panel.

Readme

strapi-plugin-data-excel-exporter

npm version License: MIT

Export Strapi v5 collection entries to .xlsx files directly from the admin panel.

Select one or more entries in any Content Manager list view; an Export action appears alongside Delete/Publish. Click it and the selected entries stream down to your browser as an Excel workbook with every flattenable field included.

Requirements

  • Strapi ^5.0.0
  • Node >=20.0.0 <=24.x.x
  • React 18

Installation

yarn add strapi-plugin-data-excel-exporter
# or
npm install strapi-plugin-data-excel-exporter

Enable the plugin in config/plugins.ts (or .js):

export default () => ({
  'data-exporter': {
    enabled: true,
  },
});

Then rebuild and start the admin:

yarn build
yarn develop

Permissions

Bulk-exporting a collection is intentionally separate from reading individual entries. After installing the plugin, grant the Export collections action to roles that should have it:

  1. Open Settings → Administration Panel → Roles.
  2. Pick a role (e.g. Editor).
  3. Under the relevant content type, tick Export collections.
  4. Save.

Users without this permission will see a 403 Forbidden toast when they try to export.

Super-admins always have access — they don't need explicit permission.

Usage

  1. Open any collection in the Content Manager.
  2. Tick the checkboxes for the rows you want to export.
  3. Click Export in the bulk-action bar that appears above the table.
  4. The .xlsx downloads automatically with every flattenable field included for the selected entries.

To export the entire collection, use the "select all" checkbox in the table header (Strapi-managed, paginates as expected).

Configuration

All keys are optional; defaults are shown.

// config/plugins.ts
export default () => ({
  'data-exporter': {
    enabled: true,
    config: {
      maxRows: 50_000,
      pageSize: 500,
      flattenDepth: 3,
      relationDisplayField: 'id',
      excludeAttributes: ['password', 'resetPasswordToken'],
      filenameTemplate: '{collection}-{date}.xlsx',
      sanitizeFormulas: true,
    },
  },
});

| Key | Default | Description | |---|---|---| | maxRows | 50000 | Hard cap on entries per export. Exports above this fail with HTTP 413. | | pageSize | 500 | Internal pagination size used while streaming. Auto-clamped to maxRows. | | flattenDepth | 3 | How many levels of nested components to flatten into dotted columns. Deeper paths are collapsed to a JSON column. Range [1, 10]. | | relationDisplayField | 'id' | Which field of a related entry to render in cells. Many-relations are joined by comma. | | excludeAttributes | ['password', 'resetPasswordToken'] | Attribute names that are never exported, regardless of selection. | | filenameTemplate | '{collection}-{date}.xlsx' | {collection}info.singularName. {date} → ISO-8601 basic UTC (e.g. 20260427T143015Z). | | sanitizeFormulas | true | If true, prepend ' to cell values starting with =/+/-/@. See Security below. |

How an export happens

admin click  →  POST /data-exporter/export
                  { uid, query: { filters: { documentId: { $in: [...] } } } }
            →  isAuthenticatedAdmin policy
            →  has-export-permission policy   (RBAC check on uid)
            →  controller validates body
            →  exporter.run
                ├─ describe(uid) → resolve flattenable fields
                ├─ documentService.count(query) → check vs maxRows
                ├─ open xlsx stream-writer
                └─ paginate documentService.findMany (page=N, pageSize)
                     └─ per entry: flatten → xlsx-writer.appendRow
                ├─ commit
                └─ return Readable
            →  controller pipes Readable to response
            →  browser downloads <collection>-<ISO>.xlsx

The export streams — entries flow from the database, through pagination, into xlsx rows, and out to the browser without ever buffering the full file in memory.

The endpoint also accepts an optional fields: string[] to restrict columns; the bulk-action UI omits it (sends every flattenable field).

What gets exported

| Strapi attribute | Exported as | |---|---| | Scalars (string, integer, boolean, date, datetime, JSON, enumeration, …) | One column each | | Components (single, nested) | Flattened into dotted columns (address.country.name) up to flattenDepth | | Repeatable components | One column, JSON-encoded array | | Dynamic zones | One column, JSON-encoded array | | Media (single) | URL string | | Relations (single) | The related entry's relationDisplayField (default: id) | | Relations (many) | Comma-joined relationDisplayField values | | Password | Always excluded |

Security: formula injection

By default (sanitizeFormulas: true), any cell value starting with =, +, -, or @ gets a leading apostrophe (') prepended. This neutralizes the well-known CSV/xlsx formula-injection vector — without it, a user who can write into a content-type field could craft a value like =HYPERLINK(...) that executes when another admin opens the exported file in Excel.

Disable only if your data is fully trusted and downstream consumers handle escaping themselves.

Limits

  • Row cap: 50,000 by default. Tune via maxRows. Exceeding it fails the export with HTTP 413 (ROW_LIMIT_EXCEEDED) before any bytes are written.
  • Request timeout: For exports near the cap (~30–60s on commodity hardware with wide schemas), make sure your Strapi/Koa requestTimeout is at least 120s. Adjust in config/server.ts:
    export default ({ env }) => ({
      // …
      requestTimeout: 120_000,
    });

FAQ

Q: Can I export every locale at once? No — Strapi's bulk-selection lives within the current locale. Switch the locale picker to export a different language, or repeat per locale.

Q: Can I customize the relation display per content type? Not in v1. relationDisplayField is global. Per-relation overrides are tracked for v2.

Q: Can I pick which columns to include? Not from the bulk action — it always exports every flattenable field. The HTTP endpoint (POST /data-exporter/export) accepts an optional fields: string[] if you want to drive it programmatically.

Q: Why is the file empty / why does my browser open the response inline? Some networks rewrite Content-Disposition headers. If filenames look generic (export.xlsx) or the file streams to the browser tab instead of downloading, check that no proxy is stripping headers between Strapi and the client.

Q: My collection has 200k rows. How do I export it? Increase maxRows and requestTimeout (and your Node memory if needed). For collections that large, an async/job-queue mode is on the roadmap for v2.

Out of scope (v1)

  • REST or CLI export triggers
  • Bulk-action on selected rows
  • Async/job-queue mode
  • Multi-sheet "full fidelity" workbooks
  • Per-relation relationDisplayField overrides
  • Strapi v4 compatibility

License

MIT — see LICENSE.