Starlark in Tilt
Starlark in Tilt
Section titled “Starlark in Tilt”Tilt is a development tool for Kubernetes that uses Starlark through Tiltfiles to define local development workflows. It automates building, pushing, and deploying containers with live updates.
What Tilt Does
Section titled “What Tilt Does”Tilt watches your filesystem, rebuilds containers, and updates running services:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐│ Edit Code │────▶│ Tilt Detects │────▶│ Live Update ││ │ │ │ │ ││ • Source files │ │ • File watcher │ │ • Sync files ││ • Dockerfiles │ │ • Dependency │ │ • Run commands ││ • K8s manifests │ │ tracking │ │ • Restart procs │└─────────────────┘ └─────────────────┘ └─────────────────┘Tiltfile Basics
Section titled “Tiltfile Basics”A Tiltfile defines your development environment:
# Tiltfile
# Build a Docker imagedocker_build('myapp/backend', './backend')
# Deploy to Kubernetesk8s_yaml('kubernetes.yaml')
# Configure the resourcek8s_resource('backend', port_forwards=8080)File Structure
Section titled “File Structure”| File | Purpose |
|---|---|
Tiltfile | Main configuration (Starlark) |
tilt_modules/ | Extensions and shared code |
.tiltignore | Files to ignore (like .gitignore) |
tilt-settings.yaml | User-specific settings |
Core Functions
Section titled “Core Functions”Building Images
Section titled “Building Images”docker_build
Section titled “docker_build”Build Docker images with automatic rebuild on file changes:
docker_build( 'myregistry/myapp', # Image reference './app', # Build context dockerfile='Dockerfile', # Dockerfile path build_args={'ENV': 'dev'},# Build arguments ignore=['tests/', '*.md'], # Files to ignore only=['src/', 'go.mod'], # Only include these live_update=[ # Live update steps sync('./src', '/app/src'), run('go build -o /app/main ./...'), ],)custom_build
Section titled “custom_build”For non-Docker builds (Bazel, ko, buildpacks, etc.):
custom_build( 'myapp/server', 'bazel build //cmd/server:image && bazel run //cmd/server:image', deps=['cmd/', 'pkg/', 'BUILD.bazel'], tag='bazel-built',)Kubernetes Deployment
Section titled “Kubernetes Deployment”k8s_yaml
Section titled “k8s_yaml”Load Kubernetes manifests:
# From filesk8s_yaml('deployment.yaml')k8s_yaml(['service.yaml', 'ingress.yaml'])
# From Helmk8s_yaml(helm('charts/myapp', values='values-dev.yaml'))
# From Kustomizek8s_yaml(kustomize('overlays/dev'))
# Inline YAMLk8s_yaml(blob("""apiVersion: v1kind: ConfigMapmetadata: name: my-configdata: key: value"""))k8s_resource
Section titled “k8s_resource”Configure how Tilt manages Kubernetes resources:
k8s_resource( 'backend', port_forwards=[ 8080, # Simple forward port_forward(9229, name='Debug'), # Named forward ], resource_deps=['database'], # Wait for dependencies labels=['backend'], # Group in UI trigger_mode=TRIGGER_MODE_MANUAL, # Manual rebuild only)Docker Compose
Section titled “Docker Compose”Tilt also works with Docker Compose:
docker_compose('docker-compose.yml')
# With overridesdocker_compose([ 'docker-compose.yml', 'docker-compose.override.yml',])
# Configure a compose servicedc_resource('redis', labels=['infra'])Live Update
Section titled “Live Update”Live Update syncs changes to running containers without rebuilding:
docker_build( 'myapp/frontend', '.', live_update=[ # Trigger full rebuild if these change fall_back_on(['package.json', 'package-lock.json']),
# Sync source files to container sync('./src', '/app/src'), sync('./public', '/app/public'),
# Run commands after sync run('npm run build', trigger=['./src']),
# For Docker Compose: restart the process restart_container(), ],)Live Update Steps
Section titled “Live Update Steps”| Step | Purpose |
|---|---|
fall_back_on(files) | Trigger full rebuild if these files change |
sync(local, remote) | Copy files to container |
run(cmd, trigger=) | Execute command in container |
restart_container() | Restart container process (Compose only) |
Local Resources
Section titled “Local Resources”Run local commands as part of your dev environment:
# Run a local scriptlocal_resource( 'codegen', cmd='./scripts/generate.sh', deps=['schema.graphql'], labels=['codegen'],)
# Serve local docslocal_resource( 'docs', serve_cmd='mkdocs serve', deps=['docs/'], links=['http://localhost:8000'],)Extensions
Section titled “Extensions”Tilt has an extension system for reusable Tiltfile code:
# Load from tilt-extensions repositoryload('ext://restart_process', 'docker_build_with_restart')load('ext://helm_resource', 'helm_resource')load('ext://secret', 'secret_from_dict')
# Use the extensiondocker_build_with_restart( 'myapp', '.', entrypoint='/app/main', live_update=[sync('./src', '/app/src')],)Popular extensions:
restart_process- Restart process without container rebuildhelm_resource- Better Helm chart supportsecret- Manage Kubernetes secretsnamespace- Auto-create namespacesconfigmap- Manage ConfigMaps
Built-in Modules
Section titled “Built-in Modules”Tiltfiles can import standard modules:
# Operating system infoload('ext://os', 'os')print(os.name) # 'posix' or 'nt'print(os.environ) # Environment variables
# Configuration from filesload('ext://config', 'config')settings = config.parse()
# Shell-style argument parsingload('ext://shlex', 'shlex')args = shlex.split('cmd --flag "with spaces"')Helper Functions
Section titled “Helper Functions”Execute local commands:
# Run a command, get output as Blobversion = local('git describe --tags')
# Use output in your Tiltfileif 'dirty' in str(version): print('Warning: uncommitted changes')read_file / read_yaml / read_json
Section titled “read_file / read_yaml / read_json”Read configuration files:
# Read raw filecontent = read_file('config.txt')
# Read and parse YAMLconfig = read_yaml('settings.yaml')print(config['database']['host'])
# Read and parse JSONpackage = read_json('package.json')print(package['version'])encode_yaml / encode_json
Section titled “encode_yaml / encode_json”Generate configuration:
# Create ConfigMap from dictconfig_data = {'LOG_LEVEL': 'debug', 'PORT': '8080'}k8s_yaml(blob(encode_yaml({ 'apiVersion': 'v1', 'kind': 'ConfigMap', 'metadata': {'name': 'app-config'}, 'data': config_data,})))Example: Full Stack App
Section titled “Example: Full Stack App”# Tiltfile for a typical web application
# === Backend (Go) ===docker_build( 'myapp/api', './api', live_update=[ sync('./api', '/app'), run('go build -o /app/server ./cmd/server'), ],)
# === Frontend (React) ===docker_build( 'myapp/web', './web', live_update=[ fall_back_on(['package.json', 'package-lock.json']), sync('./web/src', '/app/src'), ],)
# === Deploy ===k8s_yaml(kustomize('./k8s/overlays/dev'))
# === Configure Resources ===k8s_resource('api', port_forwards=8080, labels=['backend'])k8s_resource('web', port_forwards=3000, labels=['frontend'])k8s_resource('postgres', labels=['database'])
# === Local Tools ===local_resource( 'db-migrate', cmd='./scripts/migrate.sh', deps=['./migrations'], resource_deps=['postgres'], labels=['database'],)Starlark Features in Tilt
Section titled “Starlark Features in Tilt”Tilt’s Starlark supports standard features:
# Functionsdef my_service(name, port): docker_build('myapp/' + name, './' + name) k8s_yaml(name + '.yaml') k8s_resource(name, port_forwards=port)
my_service('api', 8080)my_service('worker', 9090)
# Conditionalsif os.environ.get('CI'): # CI-specific config config.define_bool('skip-tests')else: # Local development local_resource('tests', cmd='go test ./...')
# Loopsservices = ['api', 'worker', 'scheduler']for svc in services: docker_build('myapp/' + svc, './' + svc)Further Reading
Section titled “Further Reading”Source References
Section titled “Source References”This documentation is based on Tilt source code at commit cbbb93e: