Skip to main content
Complete these first:
  • Deploy Application at least once locally
  • AWS credentials configured for your CI environment

Introduction

The Fjall CLI runs in CI/CD pipelines without extra configuration. When it detects a non-interactive environment (no TTY), it switches to plain text output and returns standard exit codes. Official plugins cover GitHub Actions and Buildkite. For any other CI system, install and invoke the CLI directly.

GitHub Actions

The fjall-io/fjall-deploy-action is a composite action that installs the CLI and runs it with the right flags.

Minimal Workflow

name: Deploy
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: fjall-io/fjall-deploy-action@v1
        with:
          target: api
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_REGION: us-east-2
Use GitHub’s OIDC provider for keyless authentication. No long-lived secrets to rotate:
name: Deploy
on:
  push:
    branches: [main]

permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/deploy
          aws-region: us-east-2

      - uses: fjall-io/fjall-deploy-action@v1
        with:
          target: api
          verbose: true

With Fjall OIDC

If your app is registered with Fjall, the CLI auto-detects GitHub’s OIDC tokens. Just grant id-token: write and set your API key:
permissions:
  id-token: write
  contents: read

steps:
  - uses: actions/checkout@v4
  - uses: fjall-io/fjall-deploy-action@v1
    with:
      target: api
    env:
      FJALL_API_KEY: ${{ secrets.FJALL_API_KEY }}

Split Infrastructure and Code Deploys

Run infrastructure changes and code deploys as separate jobs for faster iteration:
jobs:
  infra:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/deploy
          aws-region: us-east-2
      - uses: fjall-io/fjall-deploy-action@v1
        with:
          target: api
          mode: infra-only

  code:
    needs: infra
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/deploy
          aws-region: us-east-2
      - uses: fjall-io/fjall-deploy-action@v1
        with:
          target: api
          mode: deploy-only

Action Inputs

InputRequiredDefaultDescription
commandnodeploydeploy, destroy, or build
targetyesApp name, organisation, platform, or account
servicenoSpecific ECS service name
modenofullfull, infra-only, or deploy-only
environmentnoFree-form CI/CD label passed to CDK synthesis
verbosenofalseEnable verbose logging
skip-buildnofalseSkip Docker build
no-cascadenofalseSkip cascade after organisation deploy
cli-versionnolatestPin fjall version
working-directoryno.Directory containing fjall-config.json
forcenofalseForce flag for destroy
The environment input is a free-form label for your own CI/CD logic. It does not select an AWS account or region. The deploy account is chosen by the active deployment target (fjall target set), and the region by your AWS credentials or the region setting.

Buildkite

The fjall-io/fjall-deploy-buildkite-plugin installs the CLI and runs it with the right flags.

Minimal Pipeline

steps:
  - label: ":rocket: Deploy"
    plugins:
      - fjall-io/fjall-deploy#v1.0.0:
          target: api

With AWS OIDC

steps:
  - label: ":rocket: Deploy"
    plugins:
      - aws-assume-role-with-web-identity#v1.0.0:
          role-arn: arn:aws:iam::123456789012:role/deploy
      - fjall-io/fjall-deploy#v1.0.0:
          target: api

Staging to Production Pipeline

steps:
  - label: ":test_tube: Staging"
    plugins:
      - fjall-io/fjall-deploy#v1.0.0:
          target: api
          environment: staging

  - wait

  - block: ":raised_hand: Deploy to Production?"

  - label: ":rocket: Production"
    plugins:
      - fjall-io/fjall-deploy#v1.0.0:
          target: api
          environment: production
          skip-build: true

Plugin Properties

PropertyRequiredDefaultDescription
commandnodeploydeploy, destroy, or build
targetyesApp name, organisation, platform, or account
servicenoSpecific ECS service name
modenofullfull, infra-only, or deploy-only
environmentnoFree-form CI/CD label passed to CDK synthesis
verbosenofalseEnable verbose logging
skip-buildnofalseSkip Docker build
no-cascadenofalseSkip cascade after organisation deploy
cli-versionnolatestPin fjall version
working-directoryno.Directory containing fjall-config.json
forcenofalseForce flag for destroy

Raw CLI Usage (Any CI System)

If you’re using a different CI system (GitLab CI, CircleCI, Jenkins, etc.), install and invoke the CLI directly.

Setup

# Install Node.js 22+ and the CLI
npm install -g @fjall/cli

# Deploy
fjall deploy api --non-interactive --skip-confirmation
The --non-interactive flag switches to plain text output. The --skip-confirmation flag suppresses interactive confirmation prompts. Both are essential for CI.

Key Flags

FlagDescription
--non-interactivePlain text output (no TUI)
--skip-confirmationSkip confirmation prompts
--infra-onlyDeploy only infrastructure
--deploy-onlyDeploy only code
--skip-buildSkip Docker build (use with --deploy-only)
--skip-migrationsSkip database migrations during this deployment
-v, --verboseEnable verbose logging
-e, --environment <env>Free-form CI/CD label passed to CDK synthesis (not an account selector)
--target <name>Override the active deployment target for this deploy
--region <region>Deploy to a specific region within the target’s account
--no-cascadeSkip cascade for organisation deploys
-f, --forceRedeploy all stacks even when no changes are detected

Exit Codes

CodeMeaning
0Success
1Failure
130Interrupted (SIGINT)

Environment Variables

VariableDescription
FJALL_API_KEYAPI key for Fjall OIDC authentication
AWS_ACCESS_KEY_IDAWS access key
AWS_SECRET_ACCESS_KEYAWS secret key
AWS_REGIONAWS region
AWS_SESSION_TOKENTemporary session token (if using STS)

Example: GitLab CI

deploy:
  image: node:22
  script:
    - npm install -g @fjall/cli
    - fjall deploy api --non-interactive --skip-confirmation --verbose
  only:
    - main

Example: CircleCI

jobs:
  deploy:
    docker:
      - image: cimg/node:22.0
    steps:
      - checkout
      - run: npm install -g @fjall/cli
      - run: fjall deploy api --non-interactive --skip-confirmation --verbose

Setting Up AWS Credentials

Whichever CI system you use, the Fjall CLI needs AWS credentials to deploy. Here are the common approaches, from most to least recommended: Most CI systems support OIDC federation with AWS. This avoids storing long-lived secrets:
  1. Create an IAM OIDC identity provider for your CI system
  2. Create an IAM role with a trust policy scoped to your repo/pipeline
  3. Use your CI’s OIDC integration to assume that role

Static Credentials

Store AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY as CI secrets. Simpler to set up but requires key rotation.

Instance Profiles

When your CI agents run on EC2 (for example, self-hosted Buildkite agents), attach an IAM instance profile with the required permissions. No credential management needed.

Next Steps

Deploy an Application

Run a full deploy locally before wiring it into CI/CD.

deploy Command Reference

Every fjall deploy flag, target, and option.

Understanding Profiles

How Fjall derives AWS profiles and selects the deploy target.

Configure a Deployment User

Scope the IAM role your pipeline assumes.