A personal project that recreates the feel of the Finder from Mac OS X 10.4–10.6 (Tiger–Snow Leopard),
designed to bring back the classic file-manager experience on modern macOS systems.
This is an unofficial, non-commercial project unrelated to Apple or the original Finder.
⚠️ If you see "'AquaFinder' is not opened" when launching it
This app isn't signed with an Apple Developer Program certificate / notarized, so this warning
appears the first time you open a freshly downloaded copy.
Restarting your Mac will not fix it.
Use one of the following:
- Open System Settings → Privacy & Security, scroll down, and click
Open Anyway next to the AquaFinder message, then launch AquaFinder again
- Or right-click (Control-click)
AquaFinder.app and choose "Open," then click "Open"
in the dialog that appears (this option doesn't show up on every macOS version — if it's missing, use method 1 instead)
- If neither works, run this in Terminal, then launch it normally:
xattr -cr /Applications/AquaFinder.app
Once approved, it opens normally with a regular double-click from then on.
Note: the "Full Disk Access" setting is unrelated to this issue.
Changelog
- 2026-09-28 — Improved stability around double-clicking to open a folder in List view, which could rarely crash — the internal folder-listing cache is now properly synchronized against concurrent access
- 2026-09-27 — Fixed image files showing a blank generic icon instead of a real content thumbnail in List and Column view (real thumbnails were previously only used in Icon view). Added "Move to Enclosing Folder" to the right-click menu (previously only reachable via the File menu / ⌘U)
- 2026-09-13 — Added File > Move to Enclosing Folder (⌘U). Moves the selected file or folder directly into the parent of wherever it currently sits — even several levels deep in Column View — without navigating there yourself and dragging between two windows. Undo (⌘Z) works with it too
- 2026-09-13 — Fixed landscape/portrait images being squashed into squares in Icon View thumbnails. Fixed Quick Look's up/down navigation jumping to unrelated files instead of following the folder's actual on-screen order. Fixed Column View's text and icons staying small even after raising the text-size setting
- 2026-09-09 — SHARED sidebar items now show their source host — e.g. "Documents (192.168.11.12)". When you SMB-mount another Mac's own Documents/Downloads via Apple ID file sharing, they came out with the exact same name as your local folders under PLACES; the host suffix tells them apart. PLACES and DEVICES items are unchanged
- 2026-08-29 — Fixed rows briefly duplicating or disappearing in List view when a sync tool (Dropbox, etc.) or a slow network share fired a burst of file-change events in quick succession. Now waits for a 300ms quiet period before reloading, instead of reloading on every single event
Main Features
- Icon view, list view, and column view
- Multiple windows and file copy & paste (⌘C / ⌘V)
- Automatic folder size calculation in list view
- Theme switching: 10.6-style graphite / 10.4-style brushed metal
- Font size and row height adjustments in settings
- Japanese and English localization
- Classic Finder features such as labels, Get Info, and Quick Look
Supported Versions
| Version | 0.1 |
| Supported OS | macOS 10.15 (Catalina) and later |
| Supported architecture | Apple Silicon (M1 and later) and Intel Mac (Universal Binary) |
Installation
- Download
AquaFinder.dmg from the button above.
- Open the DMG and drag
AquaFinder.app into the Applications folder.
-
On first launch, you will see a warning saying the app is from an unidentified developer — this is expected, not a bug.
To open it, choose either of the following methods:
- Right-click (or Control-click)
AquaFinder.app and choose Open, then click Open in the dialog.
- Open System Settings → Privacy & Security and click Open Anyway next to the AquaFinder message.
Once approved, it can be launched normally afterward.
License
Published under the MIT License.
AquaFinder isn't one big app target — it's split into about a dozen small Swift packages
(FSCore, FSUIKit, FSWindow, FSIconView, FSColumnView, FSListView, FSGetInfo, FSSidebar, FSQuickLook,
plus the AquaFinderApp shell that ties them together), and there's no storyboard or nib anywhere in it —
every window, toolbar button, and list cell gets built and positioned in code. Turns out getting a modern
NSToolbar to actually look and behave like Tiger/Snow Leopard's Finder toolbar means fighting AppKit's
own layout system more than I expected going in. Here's some of that.
Buttons that live outside NSToolbar
The back/forward and view-mode segmented controls (ClassicSegmentedControl) aren't real NSToolbarItems
at all — they're plain NSViews, floated on top of the toolbar and positioned entirely by hand.
That wasn't the first approach; see the crash below for why it changed. The tradeoff of going this
route is that everything about their position — including the window's own minimum width, worked
out from the two controls' fixed sizes plus margins plus room for the search field shrunk down to just
its icon — has to be tracked by hand instead of letting AppKit's layout system do it.
Icon loading and scrolling
Icons used to be looked up synchronously through Launch Services (not fast) the moment a cell first
painted, so opening a folder full of files meant watching icons pop in one at a time. IconCache moved
to NSCache and now gets warmed in the background as soon as a folder's listing comes back, rather than
waiting to be asked. Quick Look thumbnail requests get cancelled too, the moment their cell is recycled
mid-scroll, so flicking fast through a big folder doesn't leave a pile of thumbnail decodes running for
cells nothing shows anymore.
Bugs and lessons along the way
A cross-toolbar-item constraint that crashed on every launch. The original version of
the floating buttons tied one of them to the search field living in a different NSToolbarItem, with a
regular Auto Layout constraint. That crashed the app on every single launch — NSToolbarItemViewer
flat-out refuses to host a layout engine touched by any constraint referencing a view outside that
item's own view, and throws before the window ever gets to appear. Switching to plain floated NSViews
positioned by hand, with no cross-item constraints at all, is what actually shipped.
Same gray, different Mac. The toolbar bezel originally used NSColor(calibratedWhite:),
and the exact same drawing code somehow looked a shade different from one Mac to another. calibratedWhite
resolves through the display's own calibration / "Generic Gray" color space, so the same number can come
out at a different actual brightness depending on the display profile. Switched everything to plain
srgbRed/green/blue values instead — a fixed, absolute space, so what's specified is what gets drawn.
Column view's rename field editor opening empty. Renaming a file in Column view opened
an edit box with nothing in it. Setting a browser cell's image (needed for the file icon) silently flips
NSCell's own type to .imageCellType as an Apple-documented side effect, and the rename field editor seeds
its starting text from a text-type cell — so once the cell quietly became an image cell, there was
nothing left to seed it with. On top of that, Return-key renames start inside NSBrowser's own private
per-column NSMatrix, which never surfaces through any of NSBrowser's public methods, so there wasn't an
obvious hook to fix it from outside either. Fixed both inside the cell itself: forcing the type back to
.textCellType right after setting the image, and overriding edit(withFrame:in:editor:delegate:event:)
— the one call every rename is guaranteed to pass through, however it gets triggered.
Double-click doing nothing, exactly once. Launch straight into Icon or List view,
double-click a folder before ever switching to Column view, and nothing happened — no crash, no
error, just silence. Column view's setRoot() was calling browser.selectionIndexPath on an NSBrowser
whose view (and so its delegate) had never been loaded, since nothing had asked for that view yet. That
throws an Objective-C exception Swift code can't catch, and AppKit's own mouse-tracking loop happened to
swallow it rather than let the app crash — so navigate(to:) just quietly stopped partway through.
The fix was forcing the browser's view to load before touching it. A real crash would honestly have been
easier to track down than one that gets caught and thrown away.
Full source code is on GitHub.