Skip to main content

Installation

This page gets the tools onto your machine and an Octo project onto disk, ready to deploy.

Octo writes Terraform and hands it to Terragrunt to run, so most of the list below is tools your team already has, plus Node.js to run Octo itself.

Prerequisites​

ToolVersionWhy
Node.js20 or newerOcto is a TypeScript toolchain, and the generated project declares "engines": { "node": ">=20.0.0" }.
Terraform or OpenTofu1.6 or newerCreates the infrastructure. The floor comes from terraform.requiredVersion in your definition file, which the scaffolder sets to 1.6.0.
Terragrunt0.78 or newerOcto writes one Terragrunt module folder per module and drives them with terragrunt run --all, which arrived in 0.78.
AWS credentialsOnly if you deploy to AWS. A named profile in ~/.aws/credentials is enough. The AWS local setup guide starts from nothing.
node --version                 # v20.x or newer
terraform --version # v1.6.0 or newer, or: tofu --version
terragrunt --version
aws sts get-caller-identity # prints the account you are about to deploy into

Creating a project​

There is nothing to install globally. The octo command lives inside @quadnix/octo-build, and the scaffolder pulls it in as a project dependency:

npx @quadnix/octo-build create-app -t aws-s3-website -n hello-website
cd hello-website

That writes a directory called hello-website, runs npm install, and prints the four commands you will be running from now on. The -t flag picks which starting definition you get: aws-s3-website, aws-ecs-server, or aws-dynamodb-service. It changes only octo.yaml and, for the website template, a folder of files to upload. Everything else in the project is the same whichever one you pick.

Take aws-s3-website. Static Website deploys it, once you have put your own account number and a bucket name into it. The shop, the application the rest of the docs use, is built in a project of its own.

Here is what you get:

hello-website/
├── octo.yaml the definition file: what infrastructure you want
├── package.json four octo:* scripts, one per lifecycle step
├── src/index.ts where your own modules go, empty to start
├── .octo/ Octo's state, and it belongs in version control
├── tsconfig.json
└── website/ only from the aws-s3-website template

Two of those are worth knowing about before you touch anything.

octo.yaml is the definition file. It names the modules your infrastructure is made of and the inputs each one takes, and it is the only file most people edit. The Definition File covers it section by section.

.octo/ is where Octo records what it built. It is not a cache: delete it and the next run believes your infrastructure does not exist, which is why the scaffolded .gitignore keeps it in version control on purpose. Project Structure covers which files are committed and why.

info

The scaffolded .gitignore is a starting point. Change it to suit your team.

Running the CLI​

The generated package.json wraps the four lifecycle steps as scripts:

npm run octo:generate    # write the Terraform
npm run octo:validate # plan it, and report the plan against your intent

LOCK_ID=$(npm run --silent octo:lock) # apply and commit write shared state
npm run octo:apply -- --lockId $LOCK_ID # create the infrastructure
npm run octo:commit -- --lockId $LOCK_ID # record what was created, and release the lock

Each script points at .octo-tf, so the four steps cannot drift apart. Prefer the scripts to the binary: npm run puts node_modules/.bin on PATH, and Terraform needs to find octo there when it calls back mid-run.

Running the binary directly works too, as long as you name the output directory yourself:

node_modules/.bin/octo generate -o .octo-tf

Using OpenTofu​

Octo does not invoke the Terraform binary; Terragrunt does. Point Terragrunt at tofu through its own configuration, or per command:

npm run octo:validate -- --terraformBinary tofu

LOCK_ID=$(npm run --silent octo:lock)
npm run octo:apply -- --lockId $LOCK_ID --terraformBinary tofu

The flag sets TG_TF_PATH for that invocation only.

Adding Octo to a project you already have​

If you would rather not scaffold, install the packages directly:

npm install @quadnix/octo @quadnix/octo-aws-cdk @quadnix/octo-build @quadnix/octo-event-listeners
PackageNeeded when
@quadnix/octoAlways. The framework itself.
@quadnix/octo-buildAlways. Provides the octo command.
@quadnix/octo-aws-cdkYou are deploying to AWS using our modules.
@quadnix/octo-event-listenersYou want the console output and the journal. The definition file names them by class.

Install them at the same time and upgrade them the same way: the combination we support is the latest release of each, and Package Versions says what happens when they drift apart.

Your package.json must declare "type": "module", because Octo is ESM only. Calling it from a CommonJS codebase works, and is covered in this blog post, but that path is not regularly tested.

Then write an octo.yaml, and create a directory for state to live in. The Definition File covers what goes in it.