TeamMay 27, 20257 min read

Bootstrap Scripts: Your Team's Secret Weapon for Onboarding

A bootstrap script runs on first pull to a new machine, turning a bare OS into a fully configured development environment. Here's how to build one for your team.

What Bootstrap Scripts Are

A ConfigSync bootstrap script is a shell script stored at ~/.configsync/bootstrap.sh that runs automatically on the first pull to a new machine. It handles the one-time setup that config files alone cannot: installing package managers, system packages, applications, and development tools.

The bootstrap script is synced as part of your ConfigSync state. When you push, the script is included. When you pull on a fresh machine, ConfigSync detects that the machine has never been bootstrapped, prompts you to run the script, and executes it. One pull command transforms a bare operating system into your complete development environment.

How It Works

The bootstrap workflow is straightforward:

Bootstrap flow
# 1. On your current machine, create the bootstrap script vim ~/.configsync/bootstrap.sh # 2. Push (includes the bootstrap script) configsync push -m "add bootstrap script" # 3. On a new machine, install ConfigSync and pull pip install configsync configsync login configsync pull # ConfigSync detects first pull and prompts: # "Bootstrap script found. Run it? [Y/n]" # Type Y and the script executes.

Configuration Options

You can customize bootstrap behavior in your ConfigSync configuration:

Bootstrap config options
# In ~/.configsync/config.yaml bootstrap: # Custom script path (default: ~/.configsync/bootstrap.sh) script: ~/team/setup.sh # Skip the confirmation prompt (default: false) auto_run: true

Setting auto_run: true is useful for automated provisioning where no human is present to confirm. For interactive setups, the default prompt adds a safety check so developers can review the script before it runs.

One-time execution: ConfigSync creates a marker file after the bootstrap script runs successfully. Subsequent pulls on the same machine skip the bootstrap. To force a re-run, use configsync pull --rerun-bootstrap.

What to Put in a Bootstrap Script

A good bootstrap script is idempotent — running it twice produces the same result as running it once. Here is a complete example for a web development team:

~/.configsync/bootstrap.sh
#!/bin/bash set -euo pipefail echo "=== ConfigSync Bootstrap ===" # Install Homebrew (macOS) if [[ "$OSTYPE" == "darwin"* ]] && ! command -v brew &>/dev/null; then echo "Installing Homebrew..." /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" eval "$(/opt/homebrew/bin/brew shellenv)" fi # Install system packages echo "Installing packages from Brewfile..." brew bundle install --file=~/.Brewfile --no-lock # Install Oh My Zsh if [ ! -d "$HOME/.oh-my-zsh" ]; then echo "Installing Oh My Zsh..." sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended fi # Install Node.js via nvm if [ ! -d "$HOME/.nvm" ]; then echo "Installing nvm..." curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh" nvm install --lts fi # Clone team repositories REPOS_DIR=~/work mkdir -p "$REPOS_DIR" for repo in api frontend infrastructure; do if [ ! -d "$REPOS_DIR/$repo" ]; then echo "Cloning $repo..." git clone "git@github.com:our-org/$repo.git" "$REPOS_DIR/$repo" fi done # Set up databases if command -v docker &>/dev/null; then echo "Starting development databases..." docker compose -f ~/work/infrastructure/docker-compose.dev.yml up -d fi # macOS defaults if [[ "$OSTYPE" == "darwin"* ]]; then echo "Setting macOS defaults..." defaults write com.apple.dock autohide -bool true defaults write NSGlobalDomain AppleShowAllExtensions -bool true killall Dock 2>/dev/null || true fi echo "=== Bootstrap complete ==="

Bootstrap vs. Post-Pull Hooks

Bootstrap scripts and post-pull hooks serve different purposes:

The bootstrap script runs once on first pull. It handles one-time setup: installing Homebrew, cloning repositories, configuring macOS defaults. These are actions that only need to happen when setting up a new machine.

Post-pull hooks run on every pull. They handle recurring actions: installing new Brewfile entries, reloading shell configuration, restarting services after config changes. These are actions that should happen whenever configuration is updated.

Combined approach
# Bootstrap runs once: install Homebrew, clone repos, set up databases # Post-pull hooks run every time: install new packages, reload shell hooks: post_pull: - "brew bundle install --file=~/.Brewfile --no-lock" - "source ~/.zshrc"

The combination is powerful: the bootstrap script gets a new machine to a working state, and post-pull hooks keep it current as the team's tools and configuration evolve.

Team Onboarding in One Command

With a well-crafted bootstrap script, onboarding a new developer looks like this: hand them a machine, have them install ConfigSync and log in, run configsync pull. The bootstrap script installs their tools, clones the repos, and sets up the databases. The pull restores the team's standard configuration. Post-pull hooks install any remaining dependencies.

What used to take two days of following a wiki and asking senior developers for help now takes the time it takes Homebrew to install packages. The new developer's first commit can happen on their first day.

Ready to try ConfigSync?

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