Skip to content

About

A professional Node.js CLI that analyzes files by type, date and size, then moves/copies them into automatically categorized folders with a colored summary table. Built with TypeScript, commander, chalk and Node streams.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

🗂️ file-organizer-cli

Analyze files by type, date and size, then move or copy them into automatically categorized folders — all from the terminal, with a colorful summary table.

CI Release npm Node TypeScript License: MIT

A professional Node.js CLI tool built with commander, chalk and the node:fs/promises + Stream API — asynchronous, memory-friendly and fully tested with Jest.


✨ Features

  • 📂 Categorize by file type — 60+ extension mappings out of the box (Documents, Images, Videos, Audio, Code, Archives, …)
  • 📅 Categorize by date — YYYY-MM, YYYY-MM-DD or YYYY buckets (uses the file birth time, falling back to the modification time)
  • ⚖️ Categorize by size — configurable tiers (small, medium, large, huge)
  • 🔀 Combined dimensions — --by-type --by-date --by-size produces nested folders like Images/2026-08/Small (<1 MB)
  • 🚚 Move or copy (--mode copy leaves your originals untouched)
  • 🔍 --dry-run — preview the whole plan without touching a single byte
  • 🧩 Conflict strategies — keep, rename (adds (1)), or overwrite
  • ⚙️ JSON config file for reusable setups
  • 🎨 Colored terminal table with per-category counts and sizes
  • ⚡ Bounded parallelism so thousands of files finish fast
  • 📦 Stream-based transfers keep memory bounded for huge files

🚀 Installation

Requirements: Node.js ≥ 18.17.

# global install (recommended)
npm install -g file-organizer-cli

# or run without installing
npx file-organizer-cli --help

# or install locally and run via npm scripts
npm install --save-dev file-organizer-cli

⚡ Quick start

file-organizer ~/Downloads --dry-run           # preview what *would* happen
file-organizer ~/Downloads --by-type           # move into category folders
file-organizer ~/Downloads --mode copy -o /tmp/staging

Terminal demo

Running without flags categorizes by file type (the default dimension).

Tip: Always start with a --dry-run to review the plan. In interactive terminals, move mode also asks for confirmation before touching any file.


📖 CLI documentation

Usage: file-organizer [options] <directory>

Analyze a directory by file type, date and size, then move or copy files into
automatically categorized folders with a colored summary table.

Arguments:
  directory                     directory to analyze and organize

Options:
  -v, --version                output the current version
  -m, --mode <mode>            operation mode: move or copy (default: "move")
  -c, --conflict <strategy>    conflict handling: keep, rename or overwrite (default: "rename")
  -o, --output <dir>           root folder where categorized folders are created
  -t, --by-type                categorize by file type (default when no dimension is set)
  -d, --by-date                categorize by modification date
  -s, --by-size                categorize by size tier
  --date-format <format>       date bucket format: YYYY-MM, YYYY-MM-DD or YYYY (default: "YYYY-MM")
  -r, --recursive              recurse into sub-directories
  --max-depth <n>              maximum recursion depth (with --recursive)
  --include-hidden             process dot-files as well
  --exclude <pattern>          glob pattern(s) to skip, may be repeated
  --config <path>              path to a JSON configuration file
  --concurrency <n>            number of parallel file operations (default: 8)
  --dry-run                    preview the plan without touching the filesystem
  --verbose                    print every file operation
  --json <path>                write a JSON report of the run to this path
  -h, --help                   display help for command

Examples

Move loose files into type folders (with a confirmation prompt):

file-organizer ~/Downloads --by-type --recursive

Preview everything first:

file-organizer ~/Downloads --by-type --by-date --by-size --dry-run

Copy — originals stay in place:

file-organizer ~/Documents --mode copy --output /tmp/organized

Skip files:

file-organizer ~/Downloads --exclude '*.tmp' --exclude '/Pictures/**' --recursive

See exclude patterns for the exact matcher syntax.

Write a machine-readable report:

file-organizer ~/Downloads --json report.json

🗂️ Categorization rules

Default extension map (subset)

Presented here abbreviated; see src/core/config.ts for the full list of 60+ mappings.

Extension Folder
pdf doc docx odt txt rtf md Documents
xls xlsx ods csv Spreadsheets
jpg jpeg png gif svg webp psd ai heic Images
mp4 mkv avi mov webm m4v Videos
mp3 wav flac ogg m4a aac opus Audio
zip rar 7z tar gz bz2 iso Archives
js ts tsx py rb java c cpp go rs sh json Code
exe msi deb rpm apk appimage bin Executables
ttf otf woff woff2 eot Fonts
everything else Other

Dates use the modification time bucket when birth time is unavailable, and sizes use the thresholds below (configurable, in bytes):

Tier Default range
Small 0 – < 1 MB
Medium 1 MB – < 100 MB
Large 100 MB – < 1 GB
Huge ≥ 1 GB

Combining dimensions

--by-type --by-date --by-size nests the folders:

Images/2026-08/Small (<1 MB)/photo.jpg
Documents/2026-08/Medium (<100 MB)/thesis.pdf

🔧 Configuration file

You can keep reusable options in a JSON file and load it with --config. CLI flags always win over the config file.

{
  "mode": "move",
  "conflict": "rename",
  "recursive": true,
  "byType": true,
  "byDate": true,
  "dateFormat": "YYYY-MM",
  "exclude": ["**/.git/**", "node_modules/**", "*.tmp"],
  "concurrency": 8,
  "sizeThresholds": {
    "smallMaxBytes": 1048576,
    "mediumMaxBytes": 104857600,
    "largeMaxBytes": 1073741824
  },
  "extensionMap": {
    "psd": "Design",
    "fig": "Design",
    "sketch": "Design"
  }
}

Run it with:

file-organizer ~/Pictures --config ./file-organizer.config.json

🧶 Exclude patterns

--exclude uses a small, documented glob dialect:

Syntax Meaning Example
* any run of chars except / *.tmp
** any number of directory levels **/node_modules/**
? one char except / file?.txt
{a,b} alternation *.{png,jpg}
leading / anchors to the scan root /notes.txt (only at root)

Patterns without a leading / match at any depth (gitignore-style).


📦 JSON report

--json <path> writes the full result of the run:

{
  "dir": "/home/you/Downloads",
  "scanned": 124,
  "actions": {
    "moved": 118,
    "copied": 0,
    "skipped": 0,
    "skipped-hidden": 4,
    "conflict": 0,
    "error": 2
  },
  "operations": [ ... ],
  "summary": [ ... ]
}

🧑💻 Programmatic API

The core is exposed as a small typed API:

import { scanDirectory, categorizeFile, organize, resolveOptions } from 'file-organizer-cli';

const options = resolveOptions({ dir: './Downloads', byType: true, dryRun: true });
const { entries, errors } = await scanDirectory(options.dir, options);
const result = await organize(entries, errors, options);

console.log(result.actions); // { moved: 32, copied: 0, ... }

🧪 Testing & quality

npm install
npm test              # 49 unit tests using jest + mock-fs
npm run test:coverage # coverage report (≈90% target)
npm run lint          # eslint (typescript-eslint)
npm run format:check  # prettier formatting
npm run typecheck     # tsc --noEmit
npm run build         # produce dist/

All checks run in the CI workflow: Node 18/20/22, type-check, lint, format and tests.


🗺️ Project structure

file-organizer-cli/
├─ src/
│  ├─ cli.ts                 # commander entry point
│  ├─ commands/organize.ts   # orchestration wrapper (CLI + API)
│  ├─ core/
│  │  ├─ scanner.ts          # async directory walker (fs/promises)
│  │  ├─ categorizer.ts      # type / date / size buckets
│  │  ├─ organizer.ts        # plan + execution, streams, concurrency
│  │  └─ config.ts           # defaults, extension map, config merging
│  ├─ util/                  # pattern matching, tables, logger, sizes
│  └─ index.ts               # public API
├─ tests/                    # Jest unit tests (mock-fs)
├─ examples/                 # sample config + demo folder
└─ .github/workflows/ci.yml

🤝 Contributing

Contributions are welcome! See CONTRIBUTING.md.

📝 License

MIT © 2026 — see LICENSE.

About

A professional Node.js CLI that analyzes files by type, date and size, then moves/copies them into automatically categorized folders with a colored summary table. Built with TypeScript, commander, chalk and Node streams.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages