Feature request
Add the ability to export a collection's items to a CSV file from the CMS, mirroring the behavior that existed in the legacy Ycode app. We already support importing collections from CSV — this adds the missing export side.
Problem
Today collections can only be imported (CSVImportDialog), never exported. There's no way for a user to pull their CMS data out as a CSV — for backup, migration, editing in a spreadsheet, or re-importing elsewhere. The legacy app had this and it's a frequently expected CMS capability.
How it worked in the legacy app
For reference, the legacy (Laravel/Vue) implementation:
- An Export button in the collection data toolbar (
DataType.vue), labelled Export {n} where n reflects the number of selected items.
- Button is disabled when the collection has no items, and shows a loading spinner while the export runs.
- It exported either all items or, if rows were checked, only the selected items.
- Backend (
CollectionController::exportData) resolved the full collection (no pagination), built the CSV, stored it temporarily on disk, scheduled deletion after 10 minutes, and returned a { name, url } for download (downloadExport).
- CSV columns used the field display names as headers.
- Built-in audit columns were excluded:
Updated date, Created by, Updated by, Status (Created date was kept).
- Value flattening per field type:
- Reference → the referenced item's name field value
- Multi reference → name field values joined by
;
- Link → the URL string
Proposed solution
Implement the same flow natively in the Next.js app, reusing what we already have:
- Add an Export action in the CMS collection toolbar/UI (
app/(builder)/ycode/components/CMS.tsx), with optional "export selected vs. all" behavior based on checked items.
- Reuse the existing CSV helpers in
lib/csv-utils.ts — rowsToCSV() and downloadCSV() — already used by the redirects settings export, so no new CSV-writing code is needed.
- Build rows from collection fields + items, applying the same value-flattening rules (reference → name, multi-reference → joined names, link → URL, rich_text → HTML or plain text).
- Exclude built-in audit columns (
Updated date, Created by, Updated by, Status) to match legacy output.
- Name the file after the collection (e.g.
blog.csv).
Since the export can be generated client-side from already-loaded collection data (or via a thin repository/route fetch for the full set), we likely don't need the legacy's temp-file/storage dance — downloadCSV() triggers the browser download directly.
Open questions
- Export all items always, or respect current filters/sorting and selection (selected-only)?
- For large collections, do we fetch the full set server-side (new route/repository call) or rely on already-loaded paginated data?
- How should
rich_text be serialized — HTML, plain text, or raw TipTap JSON? (Import accepts HTML, so HTML round-trips best.)
- Should asset fields (image/video/etc.) export the public URL?
Context
We already ship the import counterpart (CSVImportDialog, collectionImportRepository, import API routes). This closes the loop. Building blocks (rowsToCSV, downloadCSV, collection field metadata) already exist in the codebase.
Feature request
Add the ability to export a collection's items to a CSV file from the CMS, mirroring the behavior that existed in the legacy Ycode app. We already support importing collections from CSV — this adds the missing export side.
Problem
Today collections can only be imported (
CSVImportDialog), never exported. There's no way for a user to pull their CMS data out as a CSV — for backup, migration, editing in a spreadsheet, or re-importing elsewhere. The legacy app had this and it's a frequently expected CMS capability.How it worked in the legacy app
For reference, the legacy (Laravel/Vue) implementation:
DataType.vue), labelledExport {n}wherenreflects the number of selected items.CollectionController::exportData) resolved the full collection (no pagination), built the CSV, stored it temporarily on disk, scheduled deletion after 10 minutes, and returned a{ name, url }for download (downloadExport).Updated date,Created by,Updated by,Status(Created date was kept).;Proposed solution
Implement the same flow natively in the Next.js app, reusing what we already have:
app/(builder)/ycode/components/CMS.tsx), with optional "export selected vs. all" behavior based on checked items.lib/csv-utils.ts—rowsToCSV()anddownloadCSV()— already used by the redirects settings export, so no new CSV-writing code is needed.Updated date,Created by,Updated by,Status) to match legacy output.blog.csv).Since the export can be generated client-side from already-loaded collection data (or via a thin repository/route fetch for the full set), we likely don't need the legacy's temp-file/storage dance —
downloadCSV()triggers the browser download directly.Open questions
rich_textbe serialized — HTML, plain text, or raw TipTap JSON? (Import accepts HTML, so HTML round-trips best.)Context
We already ship the import counterpart (
CSVImportDialog,collectionImportRepository, import API routes). This closes the loop. Building blocks (rowsToCSV,downloadCSV, collection field metadata) already exist in the codebase.