Accepted
2025-01
The local development environment had a flat directory structure under ~/repos/ that contained all
git repositories without any categorization:
~/repos/
├── some-work-project/
├── my-personal-app/
├── forked-oss-library/
├── tutorial-from-course/
├── dotfiles/
├── another-work-thing/
└── ... (many more)
This structure had several problems:
- No separation by context: Work and personal projects mixed together
- No separation by purpose: Original work, forks, and learning projects all in one place
- Difficulty finding projects: As the number of repos grew, locating specific projects became harder
- No clear ownership: Unclear which repos were forks vs. original work
- Cognitive overhead: Mental effort required to remember what each project was for
- Backup complexity: Couldn't easily back up just personal projects or exclude work projects
Additionally, the repos name was generic and didn't convey the purpose of the directory.
We migrated to a categorized directory structure under ~/Developer/:
~/Developer/
├── dotfiles/ # This repository (special case, top-level)
├── personal/ # Personal projects and side projects
│ ├── my-app/
│ └── blog/
├── work/ # Work-related repositories
│ ├── company-api/
│ └── internal-tool/
├── forks/ # Forked repositories (OSS contributions)
│ ├── neovim/
│ └── some-library/
└── learning/ # Tutorials, courses, experiments
├── rust-book-exercises/
└── nix-examples/
| Directory | Purpose | Examples |
|---|---|---|
dotfiles/ |
This configuration repository | The nix-darwin/home-manager config |
personal/ |
Original projects you own/maintain | Side projects, personal apps, blogs |
work/ |
Employer/client repositories | Company codebases, work assignments |
forks/ |
Forked repositories for contribution | OSS projects you contribute to |
learning/ |
Educational/experimental code | Course exercises, tutorials, spikes |
Developeris the macOS convention (Xcode creates~/Developer/)- More descriptive than
reposorsrcorcode - Capitalisation follows macOS convention for user-facing directories (
Documents,Downloads,Developer)
The userConfig.dotfilesPath in nix-darwin host configurations was updated to reflect the new
location:
# nix/darwin/hosts/personal.nix
{
userConfig = {
dotfilesPath = "/Users/suddenlygiovanni/Developer/dotfiles";
# ...
};
}All Nix configuration paths that referenced ~/dotfiles were updated to use
userConfig.dotfilesPath for consistency and flexibility.
- Clear mental model: Immediately know what kind of project you're looking at
- Context switching: Can focus on work vs. personal by working in different directories
- Easier navigation:
cd ~/Developer/work/<tab>shows only work projects - Selective backup: Can exclude
work/from personal backups (work has its own backup) - Clean separation: Personal git identity in
personal/, work identity inwork/ - OSS contribution tracking: All forks in one place, easy to see what you contribute to
- Learning archive: Tutorials and experiments don't clutter main project areas
- macOS convention: Follows platform conventions, familiar location
- Migration effort: One-time effort to move existing repositories
- Update git remotes: Some repos might need origin/remote URL updates
- IDE recent projects: IDE "recent projects" lists break after moving
- Symlink/script updates: Any scripts with hardcoded paths need updating
- Muscle memory: Takes time to adjust to new paths
- The structure is a convention, not enforced—discipline required to maintain organization
- New repos need a conscious decision about which category they belong to
- Some repos might fit multiple categories (judgment call required)
Continue with all repositories at the same level.
Rejected because: Doesn't scale, finding projects becomes increasingly difficult, no context separation.
~/Developer/
├── rust/
├── typescript/
├── python/
└── nix/
Rejected because: Many projects use multiple technologies. Also doesn't separate work from personal or original from forked.
Keep flat but enforce alphabetical browsing.
Rejected because: Doesn't provide any semantic organization, still mixes all contexts.
Common alternatives to ~/repos/.
Rejected because: Developer is the macOS convention and is more descriptive. src implies
source code only (not all repos are source), code is generic.
~/Developer/
├── github.com/
│ ├── suddenlygiovanni/
│ └── company-org/
├── gitlab.com/
└── bitbucket.org/
Rejected because: Overly complex, most repositories are on GitHub anyway, and doesn't convey project purpose.
Put repositories under ~/.local/src/ or similar.
Rejected because: Repositories are user-facing content, not hidden system files. They deserve a visible, easily accessible location.
When migrating from ~/repos/ to ~/Developer/:
-
Create the new structure:
mkdir -p ~/Developer/{personal,work,forks,learning} -
Move repositories by category:
mv ~/repos/my-personal-project ~/Developer/personal/ mv ~/repos/work-api ~/Developer/work/ mv ~/repos/forked-lib ~/Developer/forks/ mv ~/repos/tutorial-code ~/Developer/learning/
-
Move dotfiles (special case):
mv ~/repos/dotfiles ~/Developer/dotfiles
-
Update configuration:
- Update
userConfig.dotfilesPathin host configuration - Run
darwin-rebuild switchfrom new location
- Update
-
Update IDE/editor settings:
- Update workspace paths
- Re-open projects from new locations
-
Verify remotes (if any used relative paths):
cd ~/Developer/personal/my-project git remote -v
-
Clean up old directory:
rmdir ~/repos # Only works if empty
- Worktrees: For repos with multiple branches actively developed, consider git worktrees within the same category
- Client subdirectories: If freelancing with multiple clients, could add
~/Developer/work/{client-a,client-b}/ - Archive directory: Could add
~/Developer/archive/for old/inactive projects - Symlinks for quick access: Could symlink frequently-accessed repos to
~/Developer/top level
- Apple Developer Directory Convention
- XDG Base Directory Specification (for context on why NOT to use hidden directories)
- ADR-001: Multi-Machine Nix Configuration