Skip to content

Migration Guide

Franklin Garcia edited this page Dec 1, 2025 · 4 revisions

Migration Guide: From Legacy Helpers to Modern Type-Safe Helpers

This guide helps you migrate existing Timonel charts from legacy helpers to modern type-safe helpers.

Quick Reference

Legacy Modern Purpose
helmInclude() valuesRef() or direct values Template inclusion
helmIf() v.if() Conditionals
helmRange() v.range() Iteration
helmWith() v.with() Field-level scoping
createHelmExpression as helm valuesRef() Value interpolation

Migration Steps

Step 1: Replace helmInclude() with valuesRef()

Before:

import { Rutter, helmInclude, createHelmExpression as helm } from 'timonel';

chart.addManifest({
  metadata: {
    name: helmInclude('chart.fullname', '.'),
    labels: helmInclude('chart.labels', '.', { pipe: 'nindent 4' })
  }
}, 'deployment');

After:

import { Rutter, valuesRef } from 'timonel';

chart.addManifest({
  metadata: {
    name: 'my-app',
    labels: { app: 'my-app' }
  }
}, 'deployment');

Step 2: Replace helmIf() with v.if()

Before:

import { Rutter, helmIf, createHelmExpression as helm } from 'timonel';

chart.addManifest({
  spec: {
    replicas: helmIf('.Values.production',
      helm('{{ .Values.replicaCount | default 5 }}'),
      helm('1')
    )
  }
}, 'deployment');

After:

import { Rutter, v } from 'timonel';

chart.addManifest({
  spec: {
    replicas: v.if('production', 5, 1)
  }
}, 'deployment');

Step 3: Replace helmRange() with v.range()

Before:

import { Rutter, helmRange, createHelmExpression as helm } from 'timonel';

chart.addManifest({
  data: helmRange('$key, $value', '.Values.envVars',
    helm('{{ $key }}: {{ $value | quote }}')
  )
}, 'config');

After:

import { Rutter, v } from 'timonel';

chart.addManifest({
  data: v.range('envVars', (item) => ({
    [item.key]: item.value
  }))
}, 'config');

Step 4: Replace helmWith() with v.with()

Before:

import { Rutter, helmWith, createHelmExpression as helm } from 'timonel';

chart.addManifest({
  spec: {
    containers: [
      helmWith('container',
        helm('{{ toYaml . | nindent 8 }}')
      )
    ]
  }
}, 'pod');

After:

import { Rutter, v } from 'timonel';

chart.addManifest({
  spec: {
    containers: [
      v.with('container', {
        name: 'app',
        image: 'myapp:latest'
      })
    ]
  }
}, 'pod');

Step 5: Replace helm() with valuesRef()

Before:

import { Rutter, createHelmExpression as helm } from 'timonel';

chart.addManifest({
  spec: {
    replicas: helm('{{ .Values.replicas }}'),
    template: {
      spec: {
        containers: [{
          image: helm('{{ .Values.image.repository }}:{{ .Values.image.tag }}')
        }]
      }
    }
  }
}, 'deployment');

After:

import { Rutter, valuesRef } from 'timonel';

chart.addManifest({
  spec: {
    replicas: valuesRef('replicas'),
    template: {
      spec: {
        containers: [{
          image: valuesRef('image.repository', 'image.tag', (repo, tag) => `${repo}:${tag}`)
        }]
      }
    }
  }
}, 'deployment');

Complete Migration Example

Before (Legacy)

import { Rutter, helmInclude, helmIf, helmRange, createHelmExpression as helm } from 'timonel';

const chart = new Rutter({
  meta: { name: 'my-app', version: '1.0.0' },
  defaultValues: {
    replicas: 3,
    image: { repository: 'myapp', tag: 'latest' },
    production: false,
    envVars: { LOG_LEVEL: 'info', PORT: '8080' }
  }
});

chart.addManifest({
  apiVersion: 'apps/v1',
  kind: 'Deployment',
  metadata: {
    name: helmInclude('chart.fullname', '.'),
    labels: helmInclude('chart.labels', '.', { pipe: 'nindent 4' })
  },
  spec: {
    replicas: helmIf('.Values.production',
      helm('{{ .Values.replicas | default 5 }}'),
      helm('1')
    ),
    template: {
      spec: {
        containers: [{
          name: 'app',
          image: helm('{{ .Values.image.repository }}:{{ .Values.image.tag }}'),
          env: helmRange('$key, $value', '.Values.envVars',
            helm('{{ $key }}: {{ $value | quote }}')
          )
        }]
      }
    }
  }
}, 'deployment');

After (Modern)

import { Rutter, valuesRef, v } from 'timonel';

const chart = new Rutter({
  meta: { name: 'my-app', version: '1.0.0' },
  defaultValues: {
    replicas: 3,
    image: { repository: 'myapp', tag: 'latest' },
    production: false,
    envVars: { LOG_LEVEL: 'info', PORT: '8080' }
  }
});

chart.addManifest({
  apiVersion: 'apps/v1',
  kind: 'Deployment',
  metadata: {
    name: 'my-app',
    labels: { app: 'my-app' }
  },
  spec: {
    replicas: v.if('production', 5, 1),
    template: {
      spec: {
        containers: [{
          name: 'app',
          image: valuesRef('image.repository', 'image.tag', (repo, tag) => `${repo}:${tag}`),
          env: v.range('envVars', (item) => ({
            name: item.key,
            value: item.value
          }))
        }]
      }
    }
  }
}, 'deployment');

Environment Variables Migration

Before (Raw Helm)

import { Rutter, createHelmExpression as helm } from 'timonel';

chart.addManifest({
  spec: {
    containers: [{
      env: [
        { name: 'VERSION', value: helm('{{ .Values.global.env.VERSION | default "1.0.0" }}') },
        { name: 'LOG_LEVEL', value: helm('{{ .Values.global.env.LOG_LEVEL | default "info" }}') }
      ]
    }]
  }
}, 'deployment');

After (Modern)

import { Rutter, loadAndGenerateEnvVars } from 'timonel';

const chart = new Rutter({
  defaultValues: {
    global: {
      env: {
        VERSION: '1.0.0',
        LOG_LEVEL: 'info'
      }
    }
  }
});

const envVars = loadAndGenerateEnvVars(chart.defaultValues, 'global.env');

chart.addManifest({
  spec: {
    containers: [{
      env: envVars
    }]
  }
}, 'deployment');

Benefits of Migration

Type Safety

  • ✅ Compile-time validation
  • ✅ IDE autocomplete support
  • ✅ No runtime template errors

Code Quality

  • ✅ Cleaner, more readable code
  • ✅ Less boilerplate
  • ✅ Better maintainability

Developer Experience

  • ✅ Full IntelliSense support
  • ✅ Easier debugging
  • ✅ Better error messages

Migration Checklist

  • Update imports to use valuesRef, v instead of legacy helpers
  • Replace helmInclude() calls with direct values or valuesRef()
  • Replace helmIf() with v.if()
  • Replace helmRange() with v.range()
  • Replace helmWith() with v.with()
  • Replace helm() expressions with valuesRef()
  • Test generated Helm charts with helm lint
  • Verify deployment with helm template
  • Update documentation and examples

Troubleshooting

Issue: "Cannot find module 'timonel'"

Solution: Ensure Timonel is installed:

npm install timonel
# or
pnpm add timonel

Issue: "valuesRef is not a function"

Solution: Import from correct module:

import { valuesRef } from 'timonel';

Issue: "v.if is not a function"

Solution: Import v from timonel:

import { v } from 'timonel';

Issue: Helm template errors after migration

Solution: Validate with Helm:

helm lint ./dist
helm template my-app ./dist --debug

Getting Help

Next Steps

After migration:

  1. Review Best Practices guide
  2. Explore Advanced Examples
  3. Consider Environment Variables setup
  4. Check Umbrella Charts for complex deployments

Clone this wiki locally