Introduction
If you’ve used macOS long enough, you’ve probably noticed one thing missing compared to Windows:
👉 There is no “New File” option in Finder
For developers, this becomes frustrating very quickly. You constantly:
- Open VSCode just to create a file
- Use Terminal (
touch file.js) - Break your focus for small tasks
So instead of working around it…
👉 I built a Finder Toolbar Dev Tool
What You Will Build
By the end of this guide, you will have:
- A button in Finder toolbar
- A popup to choose:
- Stack (Laravel, Next.js, NestJS, etc.)
- File type
- Automatic file creation
- Optional boilerplate code
Who This Guide Is For
This guide works for:
Beginners
- No AppleScript knowledge needed
- Just copy-paste + follow steps
Developers
- Extendable system
- Multi-stack support
- Can evolve into full dev tool
How It Works (Concept)
Toolbar Button
↓
AppleScript Dialogs
↓
User Input (Stack + Type + Name)
↓
File Generator Logic
↓
File Created in Finder
Step 1. Open Script Editor
- Press
Cmd + Space - Type
Script Editor - Press Enter
Step 2. Create New Script
- Click New Document
- Clear everything
Step 3. Paste the Full Script
tell application "Finder"
if not (exists front window) then
display dialog "No Finder window open"
return
end if
set targetFolder to (target of front window) as alias
end tell
set basePath to POSIX path of targetFolder
-- ========================
-- SELECT STACK
-- ========================
set stackChoice to choose from list {"Laravel", "Next.js", "NestJS", "SQL", "Generic"} with prompt "Select stack:"
if stackChoice is false then return
set stack to item 1 of stackChoice
-- ========================
-- SELECT TYPE
-- ========================
if stack is "Laravel" then
set typeChoice to choose from list {"Controller", "Model", "Migration", "Blade"} with prompt "Laravel:"
else if stack is "Next.js" then
set typeChoice to choose from list {"Page", "API Route", "Component"} with prompt "Next.js:"
else if stack is "NestJS" then
set typeChoice to choose from list {"Module", "Service", "Controller"} with prompt "NestJS:"
else if stack is "SQL" then
set typeChoice to choose from list {"Migration", "Table"} with prompt "SQL:"
else
set typeChoice to choose from list {"txt", "php", "js", "md"} with prompt "Generic:"
end if
if typeChoice is false then return
set typeName to item 1 of typeChoice
-- ========================
-- FILE NAME INPUT
-- ========================
set baseName to text returned of (display dialog "Enter name:" default answer "user")
if baseName is "" then
set baseName to "NewFile"
end if
-- safer StudlyCase conversion
set studly to do shell script "echo " & quoted form of baseName & " | sed -E 's/[^a-zA-Z0-9]+/ /g' | awk '{for(i=1;i<=NF;i++){printf toupper(substr($i,1,1)) tolower(substr($i,2))}}'"
set fileName to ""
set content to ""
-- ========================
-- LARAVEL
-- ========================
if stack is "Laravel" then
if typeName is "Controller" then
set fileName to studly & "Controller.php"
set content to "<?php
namespace App\\Http\\Controllers;
use Illuminate\\Http\\Request;
class " & studly & "Controller extends Controller
{
//
}"
else if typeName is "Model" then
set fileName to studly & ".php"
set content to "<?php
namespace App\\Models;
use Illuminate\\Database\\Eloquent\\Model;
class " & studly & " extends Model
{
protected $guarded = [];
}"
else if typeName is "Migration" then
set fileName to "create_" & studly & "_table.php"
set content to "<?php
use Illuminate\\Database\\Migrations\\Migration;
use Illuminate\\Database\\Schema\\Blueprint;
use Illuminate\\Support\\Facades\\Schema;
return new class extends Migration {
public function up(): void {
Schema::create('" & studly & "', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
}
};"
else if typeName is "Blade" then
set fileName to baseName & ".blade.php"
set content to "<x-layout>
<h1>" & studly & "</h1>
</x-layout>"
end if
end if
-- ========================
-- NEXT.JS
-- ========================
if stack is "Next.js" then
if typeName is "Page" then
set fileName to "page.tsx"
set content to "export default function Page() {
return <div>" & studly & "</div>;
}"
else if typeName is "API Route" then
set fileName to "route.ts"
set content to "export async function GET() {
return Response.json({ message: '" & studly & "' });
}"
else if typeName is "Component" then
set fileName to studly & ".tsx"
set content to "export function " & studly & "() {
return <div>" & studly & "</div>;
}"
end if
end if
-- ========================
-- NESTJS
-- ========================
if stack is "NestJS" then
if typeName is "Module" then
set fileName to studly & ".module.ts"
set content to "import { Module } from '@nestjs/common';
@Module({})
export class " & studly & "Module {}"
else if typeName is "Service" then
set fileName to studly & ".service.ts"
set content to "export class " & studly & "Service {}"
else if typeName is "Controller" then
set fileName to studly & ".controller.ts"
set content to "import { Controller, Get } from '@nestjs/common';
@Controller('" & studly & "')
export class " & studly & "Controller {
@Get()
findAll() {
return [];
}
}"
end if
end if
-- ========================
-- SQL
-- ========================
if stack is "SQL" then
set fileName to studly & ".sql"
set content to "CREATE TABLE " & studly & " (
id INT PRIMARY KEY AUTO_INCREMENT
);"
end if
-- ========================
-- GENERIC
-- ========================
if stack is "Generic" then
if typeName is "php" then
set fileName to studly & ".php"
else if typeName is "js" then
set fileName to studly & ".js"
else if typeName is "md" then
set fileName to studly & ".md"
else
set fileName to studly & ".txt"
end if
end if
-- fallback safety
if fileName is "" then
set fileName to studly & ".txt"
end if
set filePath to basePath & fileName
-- ========================
-- PREVENT OVERWRITE
-- ========================
set i to 1
set originalPath to filePath
repeat while (do shell script "test -e " & quoted form of filePath & " && echo yes || echo no") is "yes"
set filePath to originalPath & "-" & i
set i to i + 1
end repeat
-- ========================
-- CREATE FILE SAFELY
-- ========================
try
do shell script "touch " & quoted form of filePath
if content is not "" then
do shell script "printf %s " & quoted form of content & " > " & quoted form of filePath
end if
on error errMsg
display dialog "Error creating file: " & errMsg
return
end try
delay 0.2
-- ========================
-- REVEAL FILE SAFELY
-- ========================
try
do shell script "test -e " & quoted form of filePath
tell application "Finder" to reveal POSIX file filePath
end try
Step 4. Save as Application
- Click File → Export
- Choose:
- Format: Application
- Name: New File
- Save in Applications
Step 5. Add to Finder Toolbar
- Open Finder
- Right-click toolbar → Customize Toolbar
- Drag your app into toolbar
- Click Done
Step 6. Use It
Now simply:
- Open any folder
- Click your toolbar button
- Select stack
- Select type
- Enter name
👉 Your file is created instantly
Developer Insights
This tool is more than a script. It’s a mini scaffolding system.
Why it’s powerful:
- Removes context switching
- Enforces naming conventions
- Works across multiple stacks
- Fully customizable
Extend It Further
You can upgrade this into:
- Laravel
artisan make:integration - NestJS CLI integration
- Template-based file system
- Auto project detection
Conclusion
Instead of adapting to limitations…
👉 You extended your OS.
You now have:
- Faster workflow
- Cleaner structure
- A tool you built yourself
And that’s where real productivity starts.