GuideSeptember 8, 20267 min read

Advanced Template Patterns: Loops, Includes, and Dynamic Configs

Go beyond simple platform checks. Learn advanced template patterns for Apple Silicon detection, tag-based feature flags, profile-driven configs, and managing work and personal settings in one file.

Why Templates Matter

Basic ConfigSync templates let you check the platform with {{platform}} and the hostname with {{hostname}}. These cover simple cases. But real development environments are more nuanced. Apple Silicon Macs need different paths than Intel Macs. GPU workstations need CUDA configuration that laptops should skip. Work and personal machines share 90% of a config but differ in important ways.

This guide covers the template patterns that handle these complex scenarios cleanly.

Pattern: OS + Architecture Combos

Apple Silicon changed the game for macOS development. Homebrew installs to /opt/homebrew on ARM64 but /usr/local on Intel. Nest conditionals to handle each combination:

Architecture-aware shell config
{{#if platform == "darwin"}} {{#if arch == "arm64"}} # Apple Silicon eval "$(/opt/homebrew/bin/brew shellenv)" export DOCKER_DEFAULT_PLATFORM=linux/amd64 {{else}} # Intel Mac eval "$(/usr/local/bin/brew shellenv)" {{/if}} {{/if}} {{#if platform == "linux"}} {{#if arch == "arm64"}} # ARM Linux (Graviton, Raspberry Pi) export PATH="/usr/local/aarch64-linux-gnu/bin:$PATH" {{else}} # x86_64 Linux export PATH="/usr/local/bin:$PATH" {{/if}} {{/if}}

These conditionals resolve at pull time. The same template file produces the correct output on every machine regardless of its architecture.

Pattern: Tag-Based Feature Flags

Machine tags let you flag capabilities that are not tied to OS or hostname. A GPU workstation, a machine with Docker installed, a high-memory build server:

Tag-based conditional blocks
# Tag your machines: # configsync machine tag --add gpu # configsync machine tag --add docker # configsync machine tag --add highmem # Then use tags in templates: {{#if tags contains "gpu"}} export CUDA_HOME="/usr/local/cuda" export PATH="$CUDA_HOME/bin:$PATH" export LD_LIBRARY_PATH="$CUDA_HOME/lib64" {{/if}} {{#if tags contains "docker"}} alias dc="docker compose" alias dps="docker ps --format 'table {{.Names}}\t{{.Status}}'" alias dlogs="docker compose logs -f" {{/if}} {{#if tags contains "highmem"}} export NODE_OPTIONS="--max-old-space-size=16384" export GRADLE_OPTS="-Xmx8g" {{/if}}
Tags are additive. A machine can have multiple tags. Your workstation tagged as "gpu", "docker", and "highmem" gets all three configuration blocks. Your laptop tagged as just "docker" gets only the Docker aliases.

Pattern: Profile-Driven Variables

Instead of branching on profile names in every config file, define variables that each profile fills differently:

Variables avoid repetitive conditionals
# ~/.configsync/config.yaml profiles: work: vars: git_email: "sean@company.com" editor: "code --wait" theme: "one-dark" font_size: "13" npm_registry: "https://registry.company.com" personal: vars: git_email: "sean@personal.dev" editor: "nvim" theme: "gruvbox" font_size: "14" npm_registry: "https://registry.npmjs.org" # ~/.gitconfig — clean, no conditionals [user] email = {{vars.git_email}} [core] editor = {{vars.editor}} # ~/.npmrc registry={{vars.npm_registry}}

Variables keep your config files readable. Instead of {{#if profile == "work"}} scattered everywhere, you reference a variable and let the profile system fill in the value.

Pattern: Work vs Personal in One File

Sometimes you need different sections rather than different values. Use profile conditionals for the parts that differ, and keep shared configuration outside any conditional:

Mixed work/personal zshrc
# Always loaded alias ll="ls -la" alias g="git" alias ..="cd .." eval "$(starship init zsh)" {{#if profile == "work"}} # Work tools and paths export JIRA_URL="https://company.atlassian.net" alias vpn="sudo openconnect vpn.company.com" alias k="kubectl --context=work-cluster" source ~/.work-secrets.sh {{/if}} {{#if profile == "personal"}} # Personal projects alias blog="cd ~/projects/blog && hugo server -D" alias homelab="ssh admin@homelab.local" alias k="kubectl --context=home-cluster" {{/if}} # Always loaded source ~/.zsh/plugins/zsh-autosuggestions.zsh source ~/.zsh/plugins/zsh-syntax-highlighting.zsh

Tips for Maintainable Templates

First, comment every conditional block. A comment like # Apple Silicon Macsaves you from deciphering nested conditions later.

Second, prefer variables over conditionals when the only difference is a single value. If work and personal differ only in an email address, use {{vars.email}} instead of a five-line conditional block.

Third, keep nesting to two levels maximum. If you need three levels of conditionals, consider splitting the file into platform-specific versions or using tags to flatten the logic.

Finally, test templates before pushing. Run configsync diff to preview what a template will produce on the current machine before committing to the change across all your devices.

Ready to try ConfigSync?

Sync your entire dev environment across machines in minutes. Free forever for up to 3 devices.