Skip to content

Instantly share code, notes, and snippets.

@felipefdl
Created April 8, 2026 15:45
Show Gist options
  • Select an option

  • Save felipefdl/391ad66d0830eb9bf2e21fef88dc9b43 to your computer and use it in GitHub Desktop.

Select an option

Save felipefdl/391ad66d0830eb9bf2e21fef88dc9b43 to your computer and use it in GitHub Desktop.
Astro build benchmark: Node vs Deno vs Bun
#!/bin/bash
# Astro production build benchmark across Node, Deno, and Bun.
# Creates git worktrees for isolation, runs builds sequentially to avoid resource contention.
#
# Requirements: git, node (via fnm), deno, bun, python3
# Usage: cd into your Astro project root, then run this script.
set -euo pipefail
RUNS=3
PROJECT_ROOT=$(git rev-parse --show-toplevel)
RESULTS_FILE="/tmp/bench-results.txt"
> "$RESULTS_FILE"
eval "$(fnm env)"
log() {
echo "[$(date +%H:%M:%S)] $1"
echo "$1" >> "$RESULTS_FILE"
}
cleanup() {
log "Cleaning up worktrees..."
for rt in node deno bun; do
git worktree remove "/tmp/bench-$rt" --force 2>/dev/null || true
git branch -D "bench-${rt}-build" 2>/dev/null || true
done
}
trap cleanup EXIT
time_build() {
local runtime="$1"
local dir="$2"
local cmd="$3"
local times=()
log "=== $runtime ==="
for i in $(seq 1 $RUNS); do
rm -rf "$dir/dist"
log " Run $i/$RUNS..."
local start=$(python3 -c 'import time; print(time.time())')
eval "$cmd" > "/tmp/bench-${runtime}-run${i}.log" 2>&1
local exit_code=$?
local end=$(python3 -c 'import time; print(time.time())')
local elapsed=$(python3 -c "print(f'{$end - $start:.2f}')")
if [ $exit_code -ne 0 ]; then
log " Run $i FAILED (exit $exit_code)"
tail -20 "/tmp/bench-${runtime}-run${i}.log"
times+=("FAIL")
else
log " Run $i: ${elapsed}s"
times+=("$elapsed")
fi
done
local valid_times=()
for t in "${times[@]}"; do
[ "$t" != "FAIL" ] && valid_times+=("$t")
done
if [ ${#valid_times[@]} -gt 0 ]; then
local csv=$(IFS=,; echo "${valid_times[*]}")
python3 -c "
times = [$csv]
avg = sum(times) / len(times)
mn = min(times)
mx = max(times)
print(f' RESULT: min={mn:.2f}s max={mx:.2f}s avg={avg:.2f}s ({len(times)}/$RUNS ok)')
" | tee -a "$RESULTS_FILE"
else
log " ALL RUNS FAILED"
fi
log ""
}
# Header
log "Astro Production Build Benchmark"
log "================================"
log "Date: $(date)"
if [[ "$(uname)" == "Darwin" ]]; then
log "Machine: $(sysctl -n machdep.cpu.brand_string)"
log "Cores: $(sysctl -n hw.ncpu) / RAM: $(sysctl -n hw.memsize | awk '{printf "%.0f GB", $1/1073741824}')"
else
log "Machine: $(cat /proc/cpuinfo | grep 'model name' | head -1 | cut -d: -f2 | xargs)"
log "Cores: $(nproc) / RAM: $(free -h | awk '/Mem:/{print $2}')"
fi
log ""
# Create worktrees
for rt in node deno bun; do
git worktree remove "/tmp/bench-$rt" --force 2>/dev/null || true
git branch -D "bench-${rt}-build" 2>/dev/null || true
git worktree add "/tmp/bench-$rt" -b "bench-${rt}-build" HEAD
done
# Install deps (npm for all three, since Deno's own installer has Vite resolution issues)
log "Installing dependencies..."
for rt in node deno bun; do
(cd "/tmp/bench-$rt" && npm install --silent 2>&1) | tail -1
done
log ""
# Node
NODE_VERSION=$(node --version)
log "Runtime: Node $NODE_VERSION"
time_build "node" "/tmp/bench-node" "cd /tmp/bench-node && node ./node_modules/.bin/astro build"
# Deno (npm-installed node_modules, deno as the JS runtime)
DENO_VERSION=$(deno --version | head -1 | awk '{print $2}')
log "Runtime: Deno $DENO_VERSION"
time_build "deno" "/tmp/bench-deno" "cd /tmp/bench-deno && deno run -A ./node_modules/.bin/astro build"
# Bun
BUN_VERSION=$(bun --version)
log "Runtime: Bun $BUN_VERSION"
time_build "bun" "/tmp/bench-bun" "cd /tmp/bench-bun && bun ./node_modules/.bin/astro build"
log "================================"
log "Full results saved to $RESULTS_FILE"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment