Migrating from Justfiles
A Justfile gives your team an ad-hoc way to run build, test, and deploy tasks, through named recipes. Atmos gives you the same capability as a native, documented feature: custom commands and workflows. Just's named parameters with default values map more directly onto Atmos flags and arguments than Make's or Task's syntax does, so this migration is direct. Your Terraform code and scripts do not need to change. Atmos replaces only the Justfile's recipes.
Install the atmos-migration skill so Claude Code, Cursor, GitHub Copilot, and other AI coding
assistants can apply this guide directly to your repository:
atmos ai skill install atmos-migration
See AI Agent Skills for details.
Why Some Teams Choose Just Over Make
Just recipes do not need tab indentation, the way Make recipes do. A recipe's parameters are
named and typed, instead of set through implicit $(VAR) substitution. Neither point changes the
migration to Atmos. A custom command does not care how the source tool formatted its recipes. It
only cares what the recipe does.
Key Concepts at a Glance
| Justfile concept | Atmos equivalent |
|---|---|
recipe param='default': | Command flags:/arguments: with a default: |
recipe: dep1 dep2 (recipe dependency) | Steps in order, or a parallel step with needs: |
# comment above a recipe | Command description: (replaces just --list) |
export VAR := value | Command or step env: map |
set dotenv-load | env: !include .env on the command, workflow, or step |
set shell := [...] | Per-step type: script with interpreter: |
[private] recipe | Command internal: true |
{{ }} interpolation | {{ .Flags.<name> }} / {{ .Arguments.<name> }} (a different tool) |
Before and After
- Before (justfile)
- After (atmos.yaml)
set dotenv-load := true
export AWS_REGION := "us-east-1"
# Build the deployable artifact
build:
go build -o bin/handler ./cmd/handler
# Run tests (builds first)
test: build
go test ./...
# Deploy to the given environment (defaults to dev)
deploy env='dev': build test
cd terraform && terraform apply -var-file=envs/{{env}}.tfvars
[private]
_clean:
rm -rf bin/
# AWS_REGION (and anything else in .env) applies to every Atmos operation, not just one
# command's own steps -- this matches the source Justfile's `set dotenv-load`/`export`,
# which apply to every recipe. A command-level `env:` map only reaches that command's own
# steps, so `test` invoking `atmos build` (a separate process) and `deploy` invoking
# `atmos test` would not inherit it.
env:
<<: !include .env
AWS_REGION: us-east-1
commands:
- name: build
description: Build the deployable artifact
steps:
- type: shell
command: go build -o bin/handler ./cmd/handler
- name: test
description: Run tests (builds first)
steps:
- type: atmos
command: build
- type: shell
command: go test ./...
- name: deploy
description: Deploy to the given environment (defaults to dev)
flags:
- name: env
shorthand: e
default: "dev"
steps:
- type: atmos
command: test
- type: atmos
command: terraform apply infra -s {{ .Flags.env }}
infra is a placeholder Atmos component name, not the terraform verb repeated. Move the old
terraform/ directory's .tf files to components/terraform/infra/ (the default
components.terraform.base_path is components/terraform), then swap infra for whatever you
actually name the component. Alternatively, keep the existing terraform/ directory where it is:
set components.terraform.base_path: "." and add metadata.component: terraform on the infra
stack component -- metadata.component points the stack component at the physical directory, so
no files need to move.
-s {{ .Flags.env }} only selects which stack runs, the way terraform.apply picks a stack by
name (dev, staging, prod); it does not, by itself, load that environment's Terraform
variables the way the source -var-file=envs/{{env}}.tfvars did. Bring the per-environment
.tfvars files in through each stack file instead, one per environment (stacks/dev.yaml,
stacks/staging.yaml, stacks/prod.yaml), each pointing at its own file. The relative path
depends on which of the two options above you picked:
See Migrating from Native Terraform for the full .tfvars/stack
mapping.
Named Parameters Become Flags and Arguments
Just's recipe param='default': syntax maps directly to Atmos flags: (or arguments: for a
positional value), each with a matching default:. Read the value inside a step as
{{ .Flags.env }}. Do not use Just's own {{env}} syntax. It is a different template engine
that runs at a different time.
Recipe Dependencies Become Steps
A recipe dependency, such as deploy: build test, gets the same treatment as a Makefile target
chain. See Migrating from Makefiles for the general method, including when
to use a parallel step instead of plain steps in order.
[private] Recipes and Environment Settings
Set internal: true on the custom command. The command still runs (atmos <name> ..., or as a
default: target, or from another command's steps), but it's excluded from atmos --help
listings and completion suggestions — matching a [private] recipe's behavior in just --list.
Reserve inlining the logic into a caller's step for a helper that's genuinely single-caller and
has no reason to be invoked on its own.
Atmos loads .env files natively with env: !include .env. Atmos parses the dotenv format
(including export VAR=value, comments, quoting, and ${VAR} expansion) and merges the result
into the command, workflow, or step env: map:
If the .env file holds secrets rather than plain configuration, prefer Atmos's store or secrets
integration instead of a plaintext .env file.
What You Gain
- A larger set of built-in step types. A Justfile recipe runs shell commands only. Atmos
adds step types for orchestration (
parallel,matrix,wait), user prompts (confirm,choose,input), and output (table,markdown,toast), with more than 30 types in total. See Step Types for the full list. - Interactive commands. A step such as
confirmorchoosecan pause a command and ask the user a question. A Justfile recipe cannot do this without a custom shell script. - Automatic tool installation. A command can list the tools it needs under
dependencies.tools. Atmos installs the correct version before the command runs. See Toolchain Configuration. A Justfile has no built-in match for this. - One interface across every command.
just --listshows recipe names and parameters. Atmos addsatmos <command> --helpwith the same flag and argument format for every command, plus typed flags, shorthands, and defaults enforced by Atmos itself.
Migration Checklist
- List every Justfile recipe. Mark each one as independent, or part of a chain
- Turn recipe parameters with defaults into command
flags:/arguments: - Turn recipe dependencies into steps in order, or into a workflow
- Turn
export VAR := valueintoenv:maps - Replace
set dotenv-loadwithenv: !include .env(or a store/secrets integration for secret values) - Mark
[private]recipes asinternal: truecustom commands - Stop relying on
just --list.atmos --helpreplaces it