If you are building full-stack apps (like a Django backend mated to a React/Vite frontend), you know the struggle of the "Locked Terminal."
You run npm run dev or python manage.py runserver, and suddenly that terminal pane is completely hijacked. To run another command, you're forced to open a brand-new tab, split your screen, or context-switch out of your flow.
Worse yet, when you hit Ctrl+C to close those servers, they sometimes leave behind "zombie processes" that stubbornly hold onto your ports (8000 or 5173), forcing you to hunt down PIDs just to restart your environment.
On my Linux setup, I got tired of managing a million tabs. Here is how to run your servers cleanly in the background and terminate them instantly using a single custom Zsh function.
The Trick: The Power of the Ampersand (&)
Most developers run their servers in the foreground. But if you append a simple & to your startup command, Linux pushes that process into the background, giving you your terminal prompt back immediately.
Instead of this:
npm run dev
# ...terminal is now locked...
Do this:
npm run dev &
What happens next? Your server spins up, its logs will still print gracefully to your screen so you can track errors, but your terminal prompt stays active. You can keep typing commands in the exact same window!
The Problem: How do you kill a background server?
Because the server is running in the background, hitting Ctrl+C won't stop it anymore. If you want to free up ports 5173 (Vite) and 8000 (Django) for your next session, you need a surgical cleanup tool.
Letβs automate this by adding a helper function to your shell configuration.
Step 1: Add the Automation to your ~/.zshrc
Open your shell config file (vim ~/.zshrc) and paste this custom function at the bottom:
# Stop background development servers and instantly free ports
stop-dev() {
echo "π Shutting down development stack..."
# 1. Forcefully kill any process holding onto our frontend/backend ports
sudo fuser -k 5173/tcp 8000/tcp 2>/dev/null
# 2. Verify the ports are completely clear
echo "π Verifying port status..."
if ! lsof -i :8000 -i :5173 > /dev/null; then
echo "β
Ports 8000 and 5173 are completely clear and ready!"
else
echo "β οΈ Warning: Some processes are still lingering."
fi
}
Save and close the file, then reload your shell environment:
source ~/.zshrc
The workflow
Now your development loop becomes incredibly smooth and single-tab friendly:
- Start your stack:
npm run dev & python manage.py runserver &
(Both servers are now running concurrently in the background of a single window!)
- Keep working: Use that same terminal prompt to run Git commands, create migrations, or check logs.
- Nuke it when done: When you're ready to wrap up your session, simply type:
stop-dev
You'll prompt for sudo password once if your cache is expired, and fuser will cleanly clear both ports out of memory instantly.
How do you manage your local full-stack setups? Let me know in the comments below!
Top comments (0)