Skip to main content

Make behavior-based overrides

If configuration overrides aren’t enough — for example, you need to skip a step, add new logic, or replace how something works — then it’s time to use a behavior override.

Behavior overrides let you change how a scope runs by customizing its workflows. You can:

  • Skip or replace workflow steps
  • Add new scripts or logic
  • Inject behavior based on conditions (like platform type or scope kind)

This is especially useful when you're building advanced scopes (like background workers or scheduled tasks) and need full control over runtime behavior.

How it works

Each scope defines its lifecycle as a set of ordered YAML steps (e.g., create, initial, delete). These workflows live in the base scope repo.

You can override those steps by placing your own workflow files in the same path inside your override repo. When the agent detects these files, it uses them instead of the default ones.

You can:

  • action: skip – ignore specific steps
  • action: replace – fully replace a step with a custom script
  • Insert your own named steps using type: script, type: command, etc.

Note: See the lifecycle execution flow for scope actions for more details.

Repo structure

Place workflow overrides under scope/workflows/ or deployment/workflows/ depending on the lifecycle action you're customizing.

your-override-repo/
├── scope/ # Scope lifecycle actions
│ └── my_domain_generator
│ └── workflows/
│ ├── create.yaml
│ ├── update.yaml
│ └── ..
├── deployment/
│ └── build_tolerations
│ └── workflows/
│ ├── initial.yaml
│ ├── blue_green.yaml
├── values.yaml # Your configuration overrides
└── ..
important

After changing your override repo, you must restart the agent so it loads the updated logic.


Example 1: Skip DNS configuration

By default, the create lifecycle step includes logic to generate a DNS record. If you're building something that doesn’t need networking — like a background worker — you can skip this step.

Create a create.yaml in your overrides repo:

your-override-repo/
├── scope/ # Scope lifecycle actions
│ └── workflows/
│ ├── create.yaml

And add a step like this:

steps:
- name: networking
action: skip

When this override is active, the networking step won't run during scope creation.


Example 2: Add tolerations for arm64 deployments

Say you want your application to run only on arm64 nodes. Kubernetes uses tolerations for this. You can inject them dynamically using a script override.

What you’ll do:

  1. Create a script that checks the asset's platform (e.g. arm_64)
  2. Add tolerations to the deployment context if needed
  3. Insert that script into the deployment workflows (initial.yaml, blue_green.yaml)

File structure

These are the files you'll need to create throughout the guide.

your-override-repo/
├── deployment/
│ └── build_tolerations # your shell script
│ └── workflows/
│ ├── initial.yaml
│ ├── blue_green.yaml
└── ..
  • In your build_tolerations script:

      #!/bin/bash

    # Find the platform of the asset being deployed
    ASSET_PLATFORM=$(echo "$CONTEXT" | jq -r .asset.platform)

    MODIFIERS=$(echo "$CONTEXT" | jq .k8s_modifiers)

    # ARM64 assets require a toleration to target the correct Kubernetes node
    if [[ "$ASSET_PLATFORM" == "arm_64" ]]; then
    TOLERATIONS='[{"key": "architecture", "operator": "Equal", "value": "arm64", "effect": "NoSchedule"}]'

    echo "The asset is built for arm, adding tolerations to the deployment"
    echo "$TOLERATIONS" | jq .

    # Add the toleration to the modifiers and
    # store it in the context so it is included in the deployment manifest
    MODIFIERS=$(echo "$MODIFIERS" | jq --argjson tolerations "$TOLERATIONS" '
    if .deployment then
    .deployment.tolerations = (.deployment.tolerations // []) + $tolerations
    else
    .deployment = {"tolerations": $tolerations}
    end
    ')

    CONTEXT=$(echo "$CONTEXT" | jq --argjson modifiers "$MODIFIERS" '.k8s_modifiers = $modifiers')
    fi

    This script modifies the deployment context only if the target architecture is arm64.

  • Then, add the step in initial.yaml:

    steps:
    - name: build_tolerations
    type: script
    file: "$OVERRIDES_PATH/deployment/build_tolerations"
    after: build context
  • Repeat the same step in blue_green.yaml if you're using both strategies.

info

$OVERRIDES_PATH points to the root of your override repo inside the agent. It’s set in your notification channel configuration as the –override-path.

Example path: /root/.np/your-org/your-repo

In both workflows, we've added a build_tolerations step that runs your custom script right after the build context step, allowing the scope to inject tolerations dynamically during deployment.


Example 3: Generate your own domain

Scopes automatically generate a domain name during the create step. If you want to control the format of that domain, you can override just the step that generates it.

File structure

your-override-repo/
├── scope/ # Scope lifecycle actions
│ └── my_domain_generator
│ └── workflows/
│ ├── create.yaml
└── ..

Here’s how to do it:

Add the replace step in create.yaml.

steps:
- name: networking
steps:
- name: generate domain
action: replace
type: script
file: "$OVERRIDES_PATH/scope/my_domain_generator"

This tells the agent to replace the generate domain step inside the networking subworkflow with a step that runs the my_domain_generator script.

Here’s a basic example of what the my_domain_generator script might look like:

SCOPE_SLUG=$(echo $CONTEXT | jq .scope.slug -r)

SCOPE_DOMAIN="$SCOPE_SLUG.acme_corp.com"

# Notify nullplatform the new domain_name
np scope patch --id "$SCOPE_ID" --body "{\"domain\":\"$SCOPE_DOMAIN\"}"


# Add the scope domain to the current and export as a global environment variable
CONTEXT=$(echo "$CONTEXT" | jq \
--arg scope_domain "$SCOPE_DOMAIN" \
'.scope.domain = $scope_domain')


export SCOPE_DOMAIN

Now your scope uses a custom domain like my-scope.acme_corp.com instead of the default.


What’s next: Combine both override types

Now that you’ve seen both configuration and behavior overrides, you can combine them to build advanced, production-ready scopes.