# How to Use Script Customization for Chain Initialization in Starship

> Master Starship chain initialization with custom scripts. Learn how to define shell scripts or inline commands in ChainScripts for complete blockchain bootstrapping control in Kubernetes.

- Repository: [Hyperweb/starship](https://github.com/hyperweb-io/starship)
- Tags: how-to-guide
- Published: 2026-03-03

---

**TLDR:** Starship enables complete control over blockchain bootstrapping by allowing users to define custom shell scripts or inline commands in the `ChainScripts` configuration, which are mounted into Kubernetes init-containers via ConfigMaps to replace or extend default genesis creation, configuration updates, and token transfer logic.

Starship, maintained by **hyperweb-io/starship**, is a Kubernetes-native development environment for Cosmos SDK blockchains. Through its **script customization for chain initialization** feature, developers can override every step of the chain bootstrapping process—from genesis file creation to validator configuration—without modifying the core codebase.

## Understanding the Script Customization Architecture

The script system relies on four coordinated components that transform user configuration into executable init-container commands.

### The ChainScripts Interface and Script Types

According to the source code in [`packages/types/src/config.ts`](https://github.com/hyperweb-io/starship/blob/main/packages/types/src/config.ts), the `ChainScripts` interface (lines 87-95) declares optional slots for each initialization phase, including `createGenesis`, `updateConfig`, and `transferTokens`. Each slot accepts a `Script` type (lines 151-157) that supports two input methods:

- **`file`**: A relative path to a shell script on the local filesystem
- **`data`**: Raw script content embedded directly in the YAML configuration

### Script Resolution with ScriptManager

Located in [`generator/src/scripts.ts`](https://github.com/hyperweb-io/starship/blob/main/generator/src/scripts.ts), the `ScriptManager` class resolves script definitions into executable content. When processing a `file` reference, it first checks the configuration directory (where the [`.starship.yaml`](https://github.com/hyperweb-io/starship/blob/main/.starship.yaml) resides), then falls back to the generator package root at `packages/generator/scripts/default/`. This resolution logic ensures test-specific scripts take precedence over bundled defaults.

### Kubernetes ConfigMap Generation and Execution

The `SetupScriptsConfigMapGenerator` in [`generator/src/builders/chains/cosmos/configmap.ts`](https://github.com/hyperweb-io/starship/blob/main/generator/src/builders/chains/cosmos/configmap.ts) (lines 24-38) transforms resolved script content into a Kubernetes ConfigMap named `setup-scripts-<chain-hostname>`. The `CosmosGenesisStatefulSetGenerator` ([`generator/src/builders/chains/cosmos/genesis.ts`](https://github.com/hyperweb-io/starship/blob/main/generator/src/builders/chains/cosmos/genesis.ts), lines 89-113) mounts this ConfigMap at `/scripts` inside the chain's init-containers.

The helper methods `getGenesisScript` and `getValidatorStartScript` (lines 595-603) provide fallback logic: if no custom script is defined, they return default definitions such as `{ name: 'create-genesis.sh', data: '/scripts/create-genesis.sh' }`, ensuring the init-container always has a valid script to execute.

## Configuring Custom Scripts in Starship

Users define scripts under the `scripts` key in their chain configuration. The system supports both external file references and inline definitions, with `ScriptManager` handling the resolution logic.

### Referencing External Script Files

To override a specific initialization step, provide a `file` path relative to your configuration directory:

```yaml
chains:
  - name: osmosis
    id: osmosis-1
    image: ghcr.io/cosmology-tech/starship/osmosis:latest
    scripts:
      createGenesis:
        file: my-scripts/custom-genesis.sh

```

As implemented in `ScriptManager`, this path resolves first against the `configDir` (the directory containing your Starship configuration), then against the package root. This allows you to keep test-specific scripts alongside your configuration files while falling back to reusable defaults shipped in the generator package.

### Embedding Inline Scripts

For short automation tasks that do not warrant separate files, embed scripts directly using the `data` field:

```yaml
chains:
  - name: juno
    id: juno-1
    image: ghcr.io/cosmology-tech/starship/juno:latest
    scripts:
      transferTokens:
        name: transfer-tokens.sh
        data: |
          #!/bin/bash
          echo "Transferring initial funds..."
          $CHAIN_BIN tx bank send $(cat /configs/faucet.mnemonic) $TARGET_ADDR 1000ujuno --keyring-backend test -y

```

The `name` field determines the filename within the generated ConfigMap. If omitted, the key name (e.g., `transferTokens`) is used with a `.sh` extension.

### Script Execution Flow in Init Containers

When `CosmosGenesisStatefulSetGenerator` creates the StatefulSet definition, it generates init-container commands that execute scripts from the mounted ConfigMap. The default genesis initialization runs:

```bash
bash -e /scripts/create-genesis.sh
bash -e /scripts/update-genesis.sh

```

When custom scripts are provided via the configuration, `SetupScriptsConfigMapGenerator` stores the custom content at these specific paths within the ConfigMap. Consequently, the init-containers execute user-defined logic instead of the default scripts, despite using identical command invocations.

## Complete Working Example

The following configuration demonstrates a custom genesis creation script that modifies governance parameters before the chain starts:

```yaml

# .starship.yaml

name: my-test
chains:
  - name: custom
    id: custom-1
    image: ghcr.io/cosmology-tech/starship/cosmos:latest
    numValidators: 1
    scripts:
      createGenesis:
        file: my-scripts/my-genesis.sh

```

```bash

# my-scripts/my-genesis.sh

#!/usr/bin/env bash
set -euo pipefail

echo "=== CUSTOM GENESIS CREATION ==="
jq '.app_state.gov.params.voting_period = "120s"' $CHAIN_DIR/config/genesis.json > /tmp/genesis.json
mv /tmp/genesis.json $CHAIN_DIR/config/genesis.json

```

During `starship generate`, the `ScriptManager` loads [`my-scripts/my-genesis.sh`](https://github.com/hyperweb-io/starship/blob/main/my-scripts/my-genesis.sh) from the configuration directory. The `SetupScriptsConfigMapGenerator` stores this content in a ConfigMap mounted at [`/scripts/create-genesis.sh`](https://github.com/hyperweb-io/starship/blob/main//scripts/create-genesis.sh). When the init-container executes `bash -e /scripts/create-genesis.sh`, it runs the custom JSON modification instead of the default genesis creation logic.

## Summary

- **Script customization for chain initialization in Starship** is controlled via the `ChainScripts` interface defined in [`packages/types/src/config.ts`](https://github.com/hyperweb-io/starship/blob/main/packages/types/src/config.ts) (lines 87-95).
- The `ScriptManager` class resolves both `file` references and inline `data`, checking the configuration directory before falling back to default package scripts in `packages/generator/scripts/default/`.
- Custom scripts are packaged into Kubernetes ConfigMaps by `SetupScriptsConfigMapGenerator` and mounted at `/scripts` in init-containers.
- Init-containers execute scripts using `bash -e /scripts/<script-name>.sh`, automatically picking up custom content when provided via the configuration.
- Both external files and embedded `data` strings are supported, allowing flexible workflow integration without core code modification.

## Frequently Asked Questions

### Can I override only specific initialization steps while keeping Starship defaults for others?

Yes. The `ChainScripts` interface defines optional slots for each phase. If you provide a custom script for `createGenesis` but omit `updateConfig`, Starship uses your custom genesis script while executing the default configuration update script located in `packages/generator/scripts/default/`.

### How does Starship locate script files referenced in the configuration?

According to the `ScriptManager` implementation in [`generator/src/scripts.ts`](https://github.com/hyperweb-io/starship/blob/main/generator/src/scripts.ts), Starship first attempts to resolve the `file` path relative to the directory containing your [`.starship.yaml`](https://github.com/hyperweb-io/starship/blob/main/.starship.yaml) configuration file. If the file does not exist there, it searches the generator package root, enabling both test-local overrides and reusable shared scripts.

### Are inline scripts suitable for complex multi-line initialization logic?

Yes. The `Script` type supports multi-line strings via the `data` field, as defined in [`packages/types/src/config.ts`](https://github.com/hyperweb-io/starship/blob/main/packages/types/src/config.ts) (lines 151-157). However, for complex logic exceeding a few lines, external files referenced via `file` provide better maintainability, version control, and syntax highlighting in your IDE.

### What happens if my custom script fails during chain initialization?

Init-containers execute with `bash -e`, which exits immediately on non-zero return codes, causing the pod initialization to fail and surface the error in Kubernetes logs. This behavior ensures faulty custom scripts halt deployment rather than proceeding with an invalid chain state, as implemented in `CosmosGenesisStatefulSetGenerator` ([`generator/src/builders/chains/cosmos/genesis.ts`](https://github.com/hyperweb-io/starship/blob/main/generator/src/builders/chains/cosmos/genesis.ts)).