Fest: solid, immutable system configuration for Arch Linux. All the power of declarative infrastructure, none of the complexity. Written in Go.
package main
import "github.com/emad-elsaid/fest"
func main() {
// Declare your entire system in Go
fest.Package("vim", "git", "docker", "firefox")
fest.SystemService("docker")
fest.Timedate("America/New_York", true)
fest.Main() // That's it. Seriously.
}
NixOS forces you to learn a new language, adopt a new distro, and rewire your mental model of Linux. Fest gives you immutable infrastructure without the friction.
You already know Go. You already love Arch. Why compromise? Get declarative configuration, reproducible systems, and version-controlled infrastructure—all while keeping the Arch Linux ecosystem you trust.
| Feature | Fest | NixOS | Ansible |
|---|---|---|---|
| Language | ✓ Go (mainstream) | Nix (custom DSL) | YAML (no type safety) |
| Type Safety | ✓ Full compiler validation | ✓ Some type checking | ✗ Runtime errors only |
| Learning Curve | ✓ Low (standard Go) | ✗ High (new paradigm) | Medium (YAML + modules) |
| Keep Your Distro | ✓ Works on Arch | ✗ Requires NixOS | ✓ Distro-agnostic |
| AUR Access | ✓ Full 80,000+ packages | ✗ Limited compatibility | ✓ Via manual tasks |
| Speed | ✓ Fast binary installs | Slow (rebuilds/downloads) | Medium (SSH overhead) |
| Single Binary | ✓ Compiled Go binary | ✗ System-level | ✗ Python + modules |
| Declarative Config | ✓ Full support | ✓ Full support | ✓ Idempotent playbooks |
| Reproducibility | ✓ Version-controlled | ✓ Fully reproducible | Depends on idempotency |
Manage pacman, AUR, Flatpak, npm, Go packages, and Ruby gems from a single declarative configuration.
Services, timers, sockets, system files, user groups, dotfiles—declare it once, sync everywhere.
Go's compiler catches typos, missing imports, and logic errors before you run a single command.
go run . diff shows exactly what would change—no surprises, no accidents.
Tracks what it installed. Remove a package from config, it gets removed from your system.
Won't remove packages other wanted packages depend on. Intelligent dependency resolution.
go run . save converts your current system state into Go code. Perfect for migrations.
Run custom logic before/after specific resources sync. Full programmatic control.
Go's simplicity and excellent tooling make Fest perfect for AI-assisted system management. LLMs understand Go naturally and leverage its compiler, formatter, and test suite.
package main
import "github.com/emad-elsaid/fest"
func main() {
// Base system packages
fest.Package(
"base-devel", "vim", "git", "htop",
"docker", "kubectl", "terraform",
)
// Development tools
fest.GoPackage(
"github.com/golangci/golangci-lint/cmd/golangci-lint@latest",
)
fest.NpmPackage(
"typescript", "@vue/cli", "eslint",
)
// Flatpak apps
fest.Flatpak(
"com.slack.Slack",
"us.zoom.Zoom",
)
// System configuration
fest.Timedate("America/New_York", true)
fest.Locale("en_US.UTF-8 UTF-8")
// Services
fest.SystemService("docker", "sshd")
fest.Service("syncthing")
// User groups
fest.Group("docker", "wheel", "audio")
// System files (from system/ directory)
fest.SystemFilesDir("system")
// Custom hook: notify after docker install
fest.After(fest.ResourcePackages, func() {
// Your custom setup logic here
})
fest.Main()
}
go run . apply on any Arch machine.
Your entire system state is now reproducible, version-controlled, and portable.
# 1. Create your system configuration
mkdir ~/mysystem && cd ~/mysystem
go mod init mysystem
go get github.com/emad-elsaid/fest
# 2. Create main.go (see examples above)
# 3. Preview what would change
go run . diff
# 4. Apply your configuration
go run . apply
# 5. Commit to git and deploy anywhere
git init && git add . && git commit -m "Initial system config"