🏭 Satis Private Repository Builder
In 18 minutes, use the Composer SDK's Satis methods to initialize config, add repositories, add require rules, and build a hostable static private Packagist. Requires local PHP + Composer.
Why Satis?
Companies have private packages that can't go on Packagist, but still want unified Composer management. Satis packages your specified private Git repos into a static website (containing packages.json), so the team can pull directly from it during composer install.
Step 1: Initialize Configuration
comp.InitSatis(name, homepage, dir) generates a satis.json skeleton in dir. You can also use CreateSatisConfig(configPath, name, homepage) to explicitly specify the config file path.
Step 2: Add Repositories & Requires
AddSatisRepository(configPath, type, url)— Append a repository to the config (typeis usuallygit/vcs).AddSatisRequire(configPath, packageName, version)— Limit which packages to build; omit to userequire-all: true.
Step 3: Build
comp.BuildSatis(configPath, outputDir) executes satis build, downloading and packaging all versions into outputDir, returning the build output text.
Complete Runnable Example
package main
import (
"fmt"
"log"
"github.com/scagogogo/composer-skills/pkg/composer"
)
func main() {
comp, err := composer.New(composer.DefaultOptions())
if err != nil {
log.Fatal(err)
}
const (
cfgPath = "/tmp/satis/satis.json"
outDir = "/tmp/satis/public"
home = "https://composer.internal.mycompany.com"
)
// 1️⃣ Initialize configuration
if err := comp.InitSatis("mycompany/satis", home, "/tmp/satis"); err != nil {
log.Fatalf("init: %v", err)
}
fmt.Println("📄 satis.json generated")
// 2️⃣ Add private VCS repositories
repos := []struct{ typ, url string }{
{"git", "https://git.internal.mycompany.com/team/auth.git"},
{"git", "https://git.internal.mycompany.com/team/billing.git"},
}
for _, r := range repos {
if err := comp.AddSatisRepository(cfgPath, r.typ, r.url); err != nil {
log.Fatalf("add repo %s: %v", r.url, err)
}
fmt.Printf("🔗 Added repository: %s\n", r.url)
}
// 3️⃣ Limit build scope (optional, omit for require-all)
if err := comp.AddSatisRequire(cfgPath, "mycompany/auth", "*"); err != nil {
log.Fatalf("add require: %v", err)
}
if err := comp.AddSatisRequire(cfgPath, "mycompany/billing", "*"); err != nil {
log.Fatalf("add require: %v", err)
}
// 4️⃣ Build
output, err := comp.BuildSatis(cfgPath, outDir)
if err != nil {
log.Fatalf("build: %v", err)
}
fmt.Println("🏗️ Build output:")
fmt.Println(output)
fmt.Printf("✅ Static repository generated at %s, containing packages.json\n", outDir)
}Expected Output
📄 satis.json generated
🔗 Added repository: https://git.internal.mycompany.com/team/auth.git
🔗 Added repository: https://git.internal.mycompany.com/team/billing.git
🏗️ Build output:
Building dev-main
Collecting packages...
✅ Static repository generated at /tmp/satis/public, containing packages.jsonStep 4: Let Projects Consume This Repository
Host the built outDir with any static server (nginx / Caddy / object storage). In the consuming PHP project, add the repository and install:
composer config repositories.mycompany composer https://composer.internal.mycompany.com
composer require mycompany/auth:"*"Advanced: Custom Configuration Structure
pkg/composer.SatisConfig is a public struct that can be directly read/written, then persisted with standard json.MarshalIndent, giving flexible control over minimum-stability, archive (offline zip packaging), providers (V2 sharding), etc.:
cfg := composer.SatisConfig{
Name: "mycompany/satis",
Homepage: home,
OutputDir: "public",
RequireAll: false,
MinimumStability: "stable",
Archive: map[string]interface{}{
"directory": "dist",
"format": "tar",
},
}
b, _ := json.MarshalIndent(cfg, "", " ")
os.WriteFile(cfgPath, b, 0644)require-all vs require
Use AddSatisRequire for precise packaging when you have few private packages — faster builds, smaller output. Use require-all: true (the InitSatis default) when you have many packages and want to expose all.
Satis Requires Separate Installation
Satis is not a built-in Composer command, must first be installed globally: composer global require composer/satis. If not installed, BuildSatis will report command not found.
Next Steps
- Add security auditing to the private repository: 🔒 Building a Security Audit Pipeline.
- Turn Satis package index statistics into a dashboard: 🪞 Package Mirror.