<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nyakio Muriuki J</title>
    <description>The latest articles on DEV Community by Nyakio Muriuki J (@nyakio).</description>
    <link>https://dev.to/nyakio</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2895889%2F5a5adef1-7b4d-4393-a687-cbba202064e9.jpeg</url>
      <title>DEV Community: Nyakio Muriuki J</title>
      <link>https://dev.to/nyakio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nyakio"/>
    <language>en</language>
    <item>
      <title>Learning `just`: A Practical Task Runner</title>
      <dc:creator>Nyakio Muriuki J</dc:creator>
      <pubDate>Thu, 03 Sep 2026 13:30:33 +0000</pubDate>
      <link>https://dev.to/nyakio/learning-just-a-practical-task-runner-2lk1</link>
      <guid>https://dev.to/nyakio/learning-just-a-practical-task-runner-2lk1</guid>
      <description>&lt;p&gt;I've been learning &lt;code&gt;just&lt;/code&gt; recently.&lt;/p&gt;

&lt;p&gt;I came across it while setting up a Python project and looking for a simple way to collect all the commands I use during development.&lt;/p&gt;

&lt;p&gt;This started with something I got used to in Elixir.&lt;/p&gt;

&lt;p&gt;One of the things I really like about Elixir projects is that you can put the common development tasks behind simple commands/aliases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mix format
mix &lt;span class="nb"&gt;test
&lt;/span&gt;mix ci
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't have to remember every command that runs underneath. The project gives you a small set of commands and you use those.&lt;/p&gt;

&lt;p&gt;I wanted something similar for a Python project.&lt;/p&gt;

&lt;p&gt;For example, instead of remembering all the different checks I need to run, I wanted to be able to do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;just ci
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and let the project take care of the rest.&lt;/p&gt;

&lt;h2&gt;
  
  
  My first thought was Make
&lt;/h2&gt;

&lt;p&gt;Make was the obvious choice.&lt;/p&gt;

&lt;p&gt;I've used Make a lot, and it works. It's installed almost everywhere, most developers have seen a Makefile before, and there is a huge amount of existing knowledge around it.&lt;/p&gt;

&lt;p&gt;So I started there.&lt;/p&gt;

&lt;p&gt;The setup was pretty small:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;format&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    uv run ruff format &lt;span class="nt"&gt;--check&lt;/span&gt; .

&lt;span class="nl"&gt;lint&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    uv run ruff check .

&lt;span class="nl"&gt;typecheck&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    uv run mypy src/

&lt;span class="nl"&gt;test&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    uv run pytest &lt;span class="nt"&gt;--cov&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;src &lt;span class="nt"&gt;--cov-report&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;term-missing

&lt;span class="nl"&gt;ci&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;format lint typecheck test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gave me exactly what I wanted.&lt;/p&gt;

&lt;p&gt;I could run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make format
make lint
make typecheck
make &lt;span class="nb"&gt;test
&lt;/span&gt;make ci
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing complicated.&lt;/p&gt;

&lt;p&gt;But while doing this, I kept seeing &lt;code&gt;just&lt;/code&gt; mentioned in newer projects.&lt;/p&gt;

&lt;p&gt;That made me curious.&lt;/p&gt;

&lt;p&gt;Not because I thought Make was bad. I still use it a lot, and I have no problem reaching for it.&lt;/p&gt;

&lt;p&gt;I just wondered what &lt;code&gt;just&lt;/code&gt; was doing differently.&lt;/p&gt;

&lt;p&gt;Was it basically Make with different syntax? Was it easier to use? Did it solve some of the small annoyances that come with Make?&lt;/p&gt;

&lt;p&gt;So I decided to rebuild the same thing in &lt;code&gt;just&lt;/code&gt; and see.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;just&lt;/code&gt; version
&lt;/h2&gt;

&lt;p&gt;The nice thing was that I didn't have to change any of the actual commands.&lt;/p&gt;

&lt;p&gt;I just changed the wrapper around them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;format:
    uv run ruff format --check .

lint:
    uv run ruff check .

typecheck:
    uv run mypy src/

test:
    uv run pytest --cov=src --cov-report=term-missing

ci: format lint typecheck test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's pretty much the whole file.&lt;/p&gt;

&lt;p&gt;Now I can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;just format
just lint
just typecheck
just &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or everything with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;just ci
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ci&lt;/code&gt; recipe depends on the other four recipes, so &lt;code&gt;just ci&lt;/code&gt; runs them in order and stops when one fails.&lt;/p&gt;

&lt;p&gt;For what I was trying to do, it felt very familiar.&lt;/p&gt;

&lt;p&gt;And that was probably the first thing I noticed. I didn't really have to learn a new way of thinking about the problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  A few things I liked about &lt;code&gt;just&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The basic syntax is very similar to Make.&lt;/p&gt;

&lt;p&gt;You have a recipe, optional dependencies, and then the commands to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;recipe_name: dependency1 dependency2
    command to run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But there are a few differences that make sense when you're using it mainly as a task runner.&lt;/p&gt;

&lt;h3&gt;
  
  
  No &lt;code&gt;.PHONY&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;With Make, you often have something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;format lint typecheck test ci&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's because Make is also a build system and cares about files and timestamps.&lt;/p&gt;

&lt;p&gt;For these development commands, I don't really need that behaviour.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;just&lt;/code&gt; doesn't use file timestamps to decide whether a recipe needs to run, so there is no &lt;code&gt;.PHONY&lt;/code&gt; declaration to maintain.&lt;/p&gt;

&lt;h3&gt;
  
  
  No tab problem
&lt;/h3&gt;

&lt;p&gt;Then there is the classic Make issue where a command needs to be indented with a tab.&lt;/p&gt;

&lt;p&gt;I've definitely lost time to that one.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;just&lt;/code&gt;, you don't have that same tab requirement. You use normal indentation.&lt;/p&gt;

&lt;p&gt;It might seem like a small thing, but I like small improvements in tools I use.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;just --list&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This was another nice surprise.&lt;/p&gt;

&lt;p&gt;You can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;just &lt;span class="nt"&gt;--list&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and get a list of the recipes available in the project.&lt;/p&gt;

&lt;p&gt;You can add comments above recipes too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Format check
format:
    uv run ruff format --check .

# Run tests
test:
    uv run pytest --cov=src --cov-report=term-missing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those comments can then show up when listing the recipes.&lt;/p&gt;

&lt;p&gt;You can also make &lt;code&gt;just&lt;/code&gt; itself show the list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;default:
    @just --list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So a developer can clone the project and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;just
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to see what is available.&lt;/p&gt;

&lt;p&gt;I like that because the task runner becomes a small piece of documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  But is &lt;code&gt;just&lt;/code&gt; actually better than Make?
&lt;/h2&gt;

&lt;p&gt;I'm not sure that's the right question.&lt;/p&gt;

&lt;p&gt;Make is still a great choice in plenty of situations.&lt;/p&gt;

&lt;p&gt;If I'm working on a project that already has a Makefile, I'm not going to suggest replacing it with &lt;code&gt;just&lt;/code&gt; just because &lt;code&gt;just&lt;/code&gt; is newer.&lt;/p&gt;

&lt;p&gt;And if I'm writing something that needs to work in an environment where Make is already installed, that is a pretty good reason to use Make.&lt;/p&gt;

&lt;p&gt;The thing I found interesting about &lt;code&gt;just&lt;/code&gt; is that it feels more focused on the thing I was actually trying to do.&lt;/p&gt;

&lt;p&gt;I wasn't building anything based on file timestamps.&lt;/p&gt;

&lt;p&gt;I just wanted names for common commands and a way to combine them.&lt;/p&gt;

&lt;p&gt;For that use case, &lt;code&gt;just&lt;/code&gt; is pretty nice.&lt;/p&gt;

&lt;p&gt;But it also comes with a trade-off. Unlike Make, you probably have to install it first.&lt;/p&gt;

&lt;p&gt;So the comparison for me looks something like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Make&lt;/th&gt;
&lt;th&gt;just&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Already installed&lt;/td&gt;
&lt;td&gt;Often&lt;/td&gt;
&lt;td&gt;Usually not&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Task runner&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build system&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.PHONY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Often needed&lt;/td&gt;
&lt;td&gt;Not needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tab requirement&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Task listing&lt;/td&gt;
&lt;td&gt;DIY&lt;/td&gt;
&lt;td&gt;Built in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-platform&lt;/td&gt;
&lt;td&gt;Possible&lt;/td&gt;
&lt;td&gt;Designed for it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Neither one wins across the board.&lt;/p&gt;

&lt;p&gt;Make has ubiquity.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;just&lt;/code&gt; has a nice developer experience.&lt;/p&gt;

&lt;p&gt;Which one makes more sense depends on the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  There are other options too
&lt;/h2&gt;

&lt;p&gt;Once I started looking into this, I found quite a few other tools doing roughly the same thing.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Task&lt;/code&gt; (go-task) was one I came across. It uses a YAML &lt;code&gt;Taskfile.yml&lt;/code&gt; and has some useful features around variables and templating.&lt;/p&gt;

&lt;p&gt;For Python, &lt;code&gt;poethepoet&lt;/code&gt; was another interesting option. It lets you put tasks in &lt;code&gt;pyproject.toml&lt;/code&gt;, which can be nice if you don't want another configuration file.&lt;/p&gt;

&lt;p&gt;And if you're working in Node, npm scripts already give you a similar setup through &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;They all solve a similar problem.&lt;/p&gt;

&lt;p&gt;You have a bunch of commands that developers need to run, and you give those commands names so people don't have to remember all the details.&lt;/p&gt;

&lt;p&gt;The differences are mostly around syntax, ecosystem, and how much functionality you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, am I switching to &lt;code&gt;just&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;For everything? No.&lt;/p&gt;

&lt;p&gt;I'm still going to use Make.&lt;/p&gt;

&lt;p&gt;If I open a project and there is a Makefile, I'll use it. If I'm working on infrastructure where Make is already expected, I'll probably use it there too.&lt;/p&gt;

&lt;p&gt;But for projects I start myself, I can see myself reaching for &lt;code&gt;just&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The thing I liked most was how little there was to learn.&lt;/p&gt;

&lt;p&gt;My existing commands stayed exactly the same. I just put a small, readable interface around them.&lt;/p&gt;

&lt;p&gt;That brought me back to why I started looking at this in the first place.&lt;/p&gt;

&lt;p&gt;In Elixir, I'm used to having commands like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mix ci
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;that give the project a simple interface for common development tasks.&lt;/p&gt;

&lt;p&gt;With Python, I found myself wanting the same thing.&lt;/p&gt;

&lt;p&gt;Make was one way to do it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;just&lt;/code&gt; is another.&lt;/p&gt;

&lt;p&gt;I'm glad I spent the time learning it. Not because it replaced Make, but because now I know another tool that fits this particular problem really well.&lt;/p&gt;

&lt;p&gt;And sometimes that's enough of a reason to try something new.&lt;/p&gt;

</description>
      <category>python</category>
      <category>ci</category>
      <category>tutorial</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
