My bachelor’s thesis was debugging and improving 1,000 lines of Makefiles for OpenMP, a giant C++ project that was originally called MP2 back in 2005. I spent months untangling dependencies, fixing parallel builds, and documenting what each target actually did.
Since then, every project I touched got a Makefile. Not because I loved Make’s syntax (nobody does), but because centralized commands are better than scattered scripts and tribal knowledge.
Then I found Just, and I haven’t looked back since.
What Make got right
Make has been around since 1976 for a reason. It solves a fundamental problem: even if your project uses robust build tools like node, ant, or gradle, you still need a clear, unified way to orchestrate all the tasks that fall outside the standard build process—setup, migrations, dev environments, cleaning, utility scripts. Those tools focus on building and packaging, but they aren’t designed to be the universal entry point for every operation your project needs. That’s why you need a layer on top: something every developer and every tool—human or AI—can rely on to run the right commands consistently.
Instead of remembering “use this docker command with these flags, then run that gradle task with this profile, oh and don’t forget to source the environment first,” you type make deploy and it works.
The Makefile documents what operations exist. It captures the correct flags and sequences. New developers read it to understand the project. Experienced developers update it instead of fixing the same command in five different places.
Make is your project’s API.
Why Just is better
Just takes Make’s core idea and fixes the pain points. Better syntax, actual error messages, simpler dependency handling. Parameters that don’t require cryptic symbols. Comments that actually help.
We organize commands into nested folders by domain: justfiles/database/Justfile, justfiles/docker/Justfile, justfiles/aws/Justfile. The root Justfile imports them all. Each domain owns its commands.
Aliases for humans
We add short aliases for commands we run constantly:
alias dbr := db-regenerate-migrations
alias dbg := db-generate-migrations
alias dba := db-apply-migrations
alias cu := compose-up
alias rd := run-dev
Type just dbr instead of just db-regenerate-migrations. Small wins compound when you’re running these dozens of times per day.
But the real benefit isn’t for humans.
The AI problem
Watch Cursor or any AI coding assistant try to run project commands without a Justfile.
You ask it to regenerate database migrations. It searches your codebase, finds script files, reads documentation, makes assumptions about which script to run, guesses at parameters, chains together commands with &&, and hopes for the best.
Sometimes it works. Often it doesn’t. When it fails, it tries a different combination. You end up with three terminal tabs of failed attempts and a confused AI that’s now trying to write its own migration script from scratch.
Next time you need the same operation, it does something completely different. No consistency. No learning. Just expensive token usage and wasted time.
What actually changes
Put your commands in a Justfile and run just --list:
Now the AI reads this. It sees dbr regenerates migrations. You ask it to regenerate migrations, it runs just dbr. Every single time. No searching, no guessing, no improvising.
The Justfile becomes the project interface for AI tools, the same way it’s the project interface for humans.
How we actually use this
At Integral, every project has a Justfile. Our modular-monolith backend service has 50+ commands organized across four domain files: database, docker, development, and AWS operations.
Database operations: just dbr regenerates the latest migration, just dbad applies migrations to local, just dbcd opens an SSH tunnel to dev database.
Docker workflows: just cub rebuilds and starts containers, just dtc runs core HTTP tests in Docker, just dtclean tears everything down.
Development cycles: just rdb starts the app in background, just dlogs -f follows logs, just dstop stops everything.
When we ask Cursor to “run tests in Docker,” it doesn’t improvise. It runs just dtc. When we need to deploy a migration to dev, it runs just dbcd then just dbad-dev. Consistent every time.
The MCP connection
Model Context Protocol servers give AI tools structured access to external systems: databases, APIs, filesystems. They’re explicit interfaces that tools can query and use reliably.
Your Justfile is the same concept at project level. It’s a structured interface to your project’s operations. AI tools can discover what’s possible (just --list), understand what each command does (from comments and names), and execute them correctly.
You don’t need to install MCP servers, configure authentication, or write integration code. You just need the Justfile you should already have.
Make it practical
Start small. Put your three most common operations in a Justfile. Add aliases. Let the team use it for a week.
Then add more. Every time someone asks “how do I run X?”, add it to the Justfile. Every time you paste a complex command in Slack, put it in the Justfile instead.
Keep commands focused. One operation per command. Use parameters for variations. Let people compose commands themselves instead of creating every combination.
Document the tricky ones. A one-line comment beats five minutes of explanation.
The real payoff
Your team runs commands correctly without checking documentation. New developers read the Justfile to understand the project. AI tools stop reinventing your build process every time you ask them to do something.
Commands stay consistent across your entire team, humans and AI both. That alone is worth the hour you’ll spend setting it up.
Make taught us that projects need APIs. Just makes those APIs readable. And in the age of AI-assisted development, readable interfaces are the difference between tools that help and tools that waste your time guessing.