ToolActToolAct

Bulk File Rename Tool

Add prefixes, suffixes, sequence numbers, find & replace, change case, modify extensions — all in your browser

Add files

Drop files here, or click the button below

Any file type and quantity, processed only in your browser — never uploaded

What is bulk file rename?

Bulk file rename is the operation of changing a group of file names in one pass according to a set of rules. Typical jobs: turning camera dumps like IMG_1234.JPG into 2026-06-trip-001.jpg, prepending @2x_ to design exports, sequencing scanned receipts by invoice date. macOS Finder's built-in rename covers Find & Replace and a name + counter format but cannot rewrite extensions; Windows Explorer's Tab-rename only adds simple sequence numbers (PowerToys PowerRename adds regex but needs a separate install). Anything more involved usually goes to desktop apps like ReNamer or Bulk Rename Utility, or to hand-rolled PowerShell / shell scripts. This tool exposes each operation — prefix/suffix, numbering, find & replace, case, extension — as a visual control with live preview and duplicate detection, so you can verify the result before downloading. The whole flow runs in browser memory, so filenames containing project codes, client names, or personal information stay on your machine.

How to use

Steps

  1. Drop files into the upload zone, or click "Select files" to pick them — adding more times appends to the list
  2. Reorder with "Sort by name / size", or use the up/down arrows on each row for fine-tuning
  3. Configure rules across the three cards: prefix/suffix, find & replace, numbering, case, extension
  4. The "New name" column updates live — blue means it differs from the original, red means it collides with another file
  5. Click "Download this file" to save individual files, or "Download as ZIP" to grab everything at once

Rule order

  • Replace the base name first (leave it empty to keep the original) — useful when you want every file to end up as e.g. "photo" plus a sequence number, regardless of its original name
  • Then find/replace runs on the base name only, never the extension
  • Numbering inserts next, as prefix, suffix, or full replacement of the base
  • Prefix and suffix wrap around the result
  • Case transformation and extension handling come last; the extension is processed independently

Use cases

Organizing camera/phone photo dumpsCamera defaults like DSC_0001.JPG or IMG_1234.JPG carry no semantic meaning. Adding a date or theme prefix and a sequence number makes albums readable at a glance. Switching the extension to lowercase prevents JPG/jpg mixes that break case-sensitive filesystems (Linux) when synced from case-insensitive ones (Windows/macOS).
iOS asset namingDesigner exports like "icon-home @2x.png" and "icon-home @3x.png" can be batched into "icon-home@2x.png" and "icon-home@3x.png" matching Xcode Asset Catalog conventions. Use find & replace to drop spaces, then lowercase the base name, to avoid case-sensitivity load failures in production.
Normalizing Android drawable namesAndroid requires resource names to be all lowercase, snake_case, with no leading digit. Mixed-case exports like IcHomeActive.png or ic-home-active.png can be batched into ic_home_active.png in one pass: replace `-` with `_`, lowercase the base, lowercase the extension. Catches the lint error before the build does.
Archiving receipts/contracts by monthScanned files like scan001.pdf–scan100.pdf lack archival context. Set the base name to "2026-06-receipts-" with 3-digit zero-padded numbering and you get "2026-06-receipts-001.pdf". Sorting by filename now equals sorting by date, and a single ZIP wraps the whole month.
Standardizing media clips for editingEditors often need to rename multi-camera footage by scene, e.g. GoPro's GH010001.MP4 → SceneA_take01.mp4. Use the base-name field to wipe the original, enable numbering, lowercase the extension — the whole batch lines up alphabetically in your NLE for easier multicam sync.
Stripping sensitive or redundant tokens from filenamesExported files often carry suffixes like (1), (copy), or _final_v2_FINAL. Find & replace cleans them in one shot. Files containing client or project codes can also be batched to anonymous codes before sharing externally — everything happens in browser memory, so originals never leave the device.
Normalizing static assets for the webBefore uploading to a CDN or object storage, normalize spaces, non-ASCII characters, and uppercase letters to avoid URL-encoding pitfalls. Replace spaces with hyphens, lowercase the base, lowercase the extension — one pass yields SEO-friendly, cross-system-safe asset names.

How it works

The whole tool runs on the browser's File API, Blob, and URL.createObjectURL — every byte stays in memory. When you drop or pick files, the browser hands JavaScript File objects (Blob subclasses) to the JS heap; the tool only reads each file's `name` property for renaming, never touching the binary content. Rules apply in a fixed order to avoid interference: first the base name is determined (user-supplied or original base), with the extension split at lastIndexOf('.') (dotfiles like .gitignore are treated as base only, no extension); then find/replace runs as String.prototype.split + Array.prototype.join (no regex — avoids unintentional special-character matching); next the sequence number is computed via `String(start + i).padStart(pad, '0')` and placed as prefix/suffix/replacement of the base; the prefix and suffix are then concatenated around the result; case transformation applies to the whole prefix+base+suffix string at once; the extension is processed independently (keep/upper/lower/replace). Duplicate detection counts each new name in a Map<string, number> during preview; names appearing more than once enter a duplicateSet that the UI highlights in red. Clicking "Download as ZIP" while the set is non-empty surfaces an error toast and aborts the pack — the original list is preserved so you can adjust the rules and try again. This runs inside useMemo([files, opts]), so rule edits incrementally recompute without re-rendering the file list. Single-file download wraps the File in URL.createObjectURL, triggers a synthetic `<a download>` click, and revokes the URL immediately. ZIP packing dynamically imports JSZip on first click (~80 KB, no first-paint cost), reads each file's arrayBuffer(), writes it under the new name, and calls generateAsync({type:'blob', compression:'DEFLATE', compressionOptions:{level:6}}). DEFLATE is the ZIP default; level 6 balances ratio against speed. Rule computation is O(n) in file count; pack time scales with total bytes. Browsers typically read File contents lazily — arrayBuffer() is when bytes actually leave disk — so even thousands of queued files cost almost nothing during preview, with the memory peak only on "Download as ZIP".

  • lastIndexOf('.') splits the extension; if the only dot is at index 0 (e.g. .gitignore) the file has no extension and the leading dot stays in the base name
  • Find & replace uses String.prototype.split + Array.prototype.join instead of replaceAll, avoiding accidental interpretation of replacement-string tokens like $1 or $& in the replacement field
  • padStart(pad, '0') generates the zero-padded number; pad=0 outputs the raw number for cases where alignment isn't needed
  • Case transformation runs after prefix/suffix are joined, so it normalizes the whole base segment at once; the extension is handled independently
  • Duplicate detection runs inside useMemo with a Map; O(n) recompute, and the UI only swaps a className for highlighted rows — no DOM rebuild
  • Blob URLs are revoked immediately via URL.revokeObjectURL to free the URL allocation pool, since reserved object URLs accumulate quickly under heavy use
  • JSZip is loaded via dynamic import only when packing is triggered, so the ~80 KB code never affects first-paint or LCP
  • DEFLATE level 6 is the browser-side sweet spot; level 9 adds 1–2% compression at 2–3× the time and barely helps for already-compressed images/video

Examples

Prefix + 3-digit zero-padded numbering

Input: photo.jpg, sunset.jpg, beach.jpg
Rules: prefix=trip2026_, start=1, pad=3, position=after
Output:
trip2026_photo001.jpg
trip2026_sunset002.jpg
trip2026_beach003.jpg

Replace base name entirely

Input: GH010001.MP4, GH010002.MP4, GH010003.MP4
Rules: base=SceneA_take, start=1, pad=2, position=after, ext=lowercase
Output:
SceneA_take01.mp4
SceneA_take02.mp4
SceneA_take03.mp4

Strip redundant suffix via find/replace

Input: report_v1_FINAL.docx, summary_v1_FINAL.docx
Rules: find=_v1_FINAL, replace=(empty), case=lowercase
Output:
report.docx
summary.docx

Replace extension

Input: index.htm, about.htm, contact.htm
Rules: extension=replace, new ext=html
Output:
index.html
about.html
contact.html

Prefix + space-to-hyphen + lowercase

Input: Banner Image.PNG, Hero Photo.JPG
Rules: prefix=web-, find=(space), replace=-, case=lowercase, extension=lowercase
Output:
web-banner-image.png
web-hero-photo.jpg

FAQ

Are my files uploaded to a server?

No. From adding files to producing new names to packing the ZIP, everything runs locally in your browser. No upload requests are made. You can verify in your browser's DevTools Network panel.

Why isn't my .gitignore / .bashrc treated as having an extension?

The tool splits on the last dot, but if the only dot is at the very start (a dotfile), the whole name is treated as the base — this avoids mistaking a hidden-prefix marker for an extension.

What happens if my new names collide?

The preview list highlights duplicates in red and shows a count badge. Clicking "Download as ZIP" while there are duplicates is blocked with an error message — your file list isn't lost, just adjust the rules and try again. Common fixes: enable numbering, increase pad width, add a prefix/suffix.

Can it rename folders / preserve nesting?

Not yet. The current version handles a single flat file list. For directory-aware bulk renaming, rename the files here and then assemble the directory tree using the ZIP Pack tool.

Does find & replace support regex?

No. It uses literal string matching (split-join) on purpose, so users can't accidentally trigger replacement-string tokens like $1 or $& in their replacement field. Plain matching covers the vast majority of cleanup needs.

How many files can it handle?

There's no hard cap on count — preview is essentially free. Packing is bounded by browser memory: very large totals (multi-GB) may fail to allocate a single Blob, in which case split your files into batches and pack each separately.

The downloaded ZIP shows garbled non-ASCII names. Why?

JSZip writes UTF-8 filenames by default, which modern extractors (macOS Archive Utility, Windows 11 Explorer, 7-Zip, WinRAR 5+) read correctly. Old Windows Explorer on Win 7/8 may still mis-decode non-Latin names — use 7-Zip or Bandizip instead.

Can I undo a rename if I made a mistake?

Renames only happen at download time — until you click "Download as ZIP" or "Download this file", the original files on disk are untouched. The preview is fully reversible: clear the rules, edit them, or remove individual files from the list. If you've already downloaded, just adjust the rules and download again with the same source files.