Bulk actions

Renaming thirty files by hand is exactly the sort of job a CMS should do for you, and exactly the sort of job that’s miserable through a web form one file at a time. Bulk actions let you select entries in a section’s list and rename, move, publish, unpublish, edit a frontmatter field, create translations or delete the lot in one go. On GitHub-hosted sites each action is a single commit.

Selecting entries#

Click the checklist icon (Select entries) in the entry list header. Each card gets a checkbox, and the header buttons are replaced by an action bar with a select-all checkbox, a count and one icon button per action. Shift-click selects a range from the last entry you toggled. Esc or the X leaves selection mode.

Selection follows the list you can see. With a search or status filter active, the checkbox selects only the matching entries, and entries that drop out of the filter drop out of the selection too. Subfolders aren’t selectable, so an action works on entries in the folder you’re looking at, not everything beneath it.

Every action opens a modal, and nothing happens until you confirm it.

Rename with pattern#

A JavaScript regular expression applied to each entry’s editable name: the filename without its extension for an ordinary entry, or the folder name for a leaf bundle (my-post/index.md), which is the same part a single-entry rename edits. Capture groups work, so ^(\d+)-draft- with replacement $1- turns 01-draft-intro into 01-intro.

The preview updates as you type, with a chip next to each entry:

Chip Meaning
Rename Will be renamed.
No match The pattern doesn’t change this name.
Section index _index.md files are never renamed.
Invalid The result has characters outside letters, digits, -, _ and ., or is index or _index.
Collision Two selected entries would end up with the same name.
Exists An entry or folder with that name is already there.

Only Rename rows are applied; the button tells you how many. Entries with unsaved changes in an open editor are skipped at the last moment and counted in the result.

Mark as draft and Publish (unmark draft)#

Mark as draft sets draft: true on each entry; Publish (unmark draft) sets draft: false. Entries already in the target state are skipped, and so are entries with unsaved changes, which the modal warns you about. Neither touches dates, so an entry dated in the future stays scheduled after you publish it.

Move to folder#

Pick a destination: the section root (when you’re in a subfolder), one of the current folder’s subfolders, or a name for a new one. Leaf bundles move as a whole folder, page resources included. Section index files, entries with unsaved changes, entries already in the destination and entries whose name is taken there are all skipped.

Moves never overwrite. The commit itself re-checks every destination against the repository tree, so a stale listing can only cause a clean abort, not a lost file.

Edit frontmatter field#

Set or remove one top-level key. The field name box suggests the section’s configured fields but takes anything. The value is parsed as YAML, so true, 3 and 2026-07-24 become a boolean, a number and a date, and a badge shows which; anything else stays a string. Tick Remove this field instead to delete the key.

Each file is re-read from the repository (bypassing the cache) before it’s rewritten, entries where the key already has that value are skipped, and the whole frontmatter block is re-serialised, which drops comments and normalises quoting the same way an ordinary save does. Changing title or date gets a warning, because the list is sorted and labelled by them.

Create translations#

Multilingual sites only. Pick a target language and Emet copies each entry to that language’s path, adjusting the frontmatter keys that are language-specific. If a Missing in filter is active when you open the dialog, that language is preselected, so “filter to what’s missing in German, select all, create translations” is three clicks. It’s a copy, not a translation; see Translation workflow for what to do next. Entries that already have a translation are skipped, entries whose status isn’t loaded yet are “checked on apply”, and the new files aren’t opened in the editor.

Mark copies as drafts is ticked by default. With it on, every copy gets draft: true, and the commit carries the site’s skip-CI marker (deploy.skip_ci, [skip ci] unless you’ve changed it), so a site that deploys on push neither rebuilds nor publishes a batch of target-language pages still showing the source text. You then translate each copy and unmark it as a draft when it’s ready. Untick it only if you want the copies live immediately as they are: the commit then triggers the deploy like any other bulk action.

Delete#

Lists every file to be deleted, flags any with unsaved changes (those changes go too), and skips section index files. Leaf bundles are deleted with their whole folder. The files remain in Git history, but Emet has no undo.

How the commit works#

On GitHub-hosted sites every bulk action is a single commit via the Git Trees API: either all of it lands or none of it does, and it goes up immediately rather than through the sync queue. Messages are of the form Rename 3 entries, Move 2 entries to archive, Set tags on 5 entries, Delete 4 entries or Create 3 fr translations. The only one that carries the skip-CI suffix is Create translations with “Mark copies as drafts” on, since every file in that commit is a draft Hugo wouldn’t build anyway.

If the branch moves while the action is running (another editor saved, say), moves, renames and deletes are rebuilt once on the new head and retried. Actions that rewrite file contents (draft, publish, field edits, translations) abort instead with “The branch changed while this operation was running”, and nothing is changed; just run it again.

Afterwards a toast reports the outcome, e.g. “Moved 4 entries (1 skipped)”. Open editors follow along: renamed and moved entries re-point to their new path, rewritten entries reload and deleted ones close.

In local and desktop mode there’s no batching. Operations are applied to the filesystem one at a time, so a failure part-way through leaves the earlier ones done.