Skip to content

Environments

Kyku has built-in workspace support for managing multiple environments (dev, staging, prod) from a single config.

Terminal window
kyku plan --env=dev # → .kyku/state.dev.json
kyku apply --env=staging # → .kyku/state.staging.json
kyku plan --env=prod # → .kyku/state.prod.json
kyku plan # → .kyku/state.json (default)

Each environment has its own:

  • State file — separate .kyku/state.<env>.json
  • Deploy prefix — unique 8-char hex prefix per env (e.g., a3f27b1d-web-server)
  • Cloud resources — completely isolated from other environments

Use TypeScript to parameterize your config:

infrastructure.ts
import { Vpc, Vm, SecurityGroup } from '@kykucloud/types';
const env = process.env.KYKU_ENV || 'dev';
const configs = {
dev: {
instanceType: 'micro' as const,
instanceCount: 1,
distAzs: 1,
},
staging: {
instanceType: 'small' as const,
instanceCount: 2,
distAzs: 2,
},
prod: {
instanceType: 'medium' as const,
instanceCount: 3,
distAzs: 3,
},
};
const cfg = configs[env as keyof typeof configs];
const vpc = new Vpc({
id: 'vpc-main',
name: `app-vpc-${env}`,
cidr: '10.0.0.0/16',
region: 'us-east',
distributeAcrossAzs: cfg.distAzs,
});
const sg = new SecurityGroup({
id: 'sg-web',
name: `web-sg-${env}`,
ingress: [
{ protocol: 'tcp', fromPort: 80, toPort: 80, sources: ['0.0.0.0/0'] },
],
});
const servers = Array.from({ length: cfg.instanceCount }, (_, i) =>
new Vm({
id: `vm-web-${i}`,
name: `web-server-${i}`,
instanceType: cfg.instanceType,
image: 'ubuntu-24.04',
network: vpc,
securityGroups: [sg],
})
);
export default { provider: 'aws', resources: [vpc, sg, ...servers] };

Each environment gets a unique 8-character hex deploy prefix, auto-generated on first plan/apply and stored in StateFile.metadata.prefix.

Environment Prefix Example Resource Name
dev a3f27b1d a3f27b1d-web-server-0
staging c8e41f9a c8e41f9a-web-server-0
prod b7d12e83 b7d12e83-web-server-0

This prevents name collisions when managing multiple environments in the same cloud account.

Custom prefix:

// In your config or engine init
const engine = new KykuEngine({
deployPrefix: 'myapp', // Custom prefix instead of random hex
});
name: Deploy
on:
push:
branches:
- main # → prod
- dev # → dev
- staging # → staging
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: |
ENV=${{ github.ref_name }}
kyku apply --env=$ENV --auto-approve
env:
KYKU_PASSPHRASE: ${{ secrets.KYKU_PASSPHRASE }}

State files are fully isolated per environment:

.kyku/
├── state.json # default
├── state.dev.json # dev
├── state.staging.json # staging
└── state.prod.json # prod

Each state file contains its own:

  • Encryption metadata (salt, IV)
  • Resource tracking (provider IDs, outputs)
  • Deploy prefix

For larger differences between environments, use separate config files:

Terminal window
kyku plan --config=./infrastructure.dev.ts --env=dev
kyku plan --config=./infrastructure.prod.ts --env=prod
  • Use --env consistently: Always pass --env to avoid mixing environments in the default state file.
  • CI matches env to branch: Map branches to environments automatically.
  • Separate credentials: Use different cloud accounts or IAM roles per environment.
  • Passphrase per env: Consider different KYKU_PASSPHRASE values per environment.
  • Destroy selectively: kyku destroy --env=dev only destroys dev resources.