Adopt hx in an existing Cabal project.
Overview
Migrating from plain Cabal to hx is straightforward because hx uses Cabal under the hood. You’re not replacing Cabal—you’re adding a better interface on top.
Quick Migration
cd my-cabal-project
# Initialize hx
hx init
# Generate lockfile
hx lock
# Build (uses existing Cabal setup)
hx buildWhat Changes
| Before (Cabal) | After (hx) |
|---|---|
cabal build | hx build |
cabal test | hx test |
cabal.project | Keep + add hx.toml |
cabal.project.freeze | hx.lock (replaces) |
What Stays the Same
*.cabalfiles — No changes neededcabal.project— Keep all settings- Source files — No changes
- Build output — Same location
Step-by-Step Migration
1. Initialize hx
cd my-project
hx init --detectThis creates hx.toml:
[project]
name = "my-project"
version = "0.1.0"
[toolchain]
ghc = "9.8.2" # Detected from environment
[build]
ghc-options = ["-Wall"]2. Handle cabal.project
If you have a cabal.project, hx respects it:
-- cabal.project
packages: .
-- hx reads these settings
ghc-options: -WallYou can optionally migrate settings to hx.toml:
# hx.toml
[build]
ghc-options = ["-Wall"]3. Handle cabal.project.freeze
If you have a freeze file:
# hx can import it
hx lock
# Or keep using Cabal freeze format
# Configure in hx.toml:
# [dependencies]
# lock-strategy = "cabal-freeze"4. Generate Lockfile
hx lockCreates hx.lock with all pinned versions.
5. Verify Everything Works
hx build
hx test
hx checkKeeping Compatibility
For Teams Not Ready for hx
Keep both working:
# Team members using Cabal
cabal build
# Team members using hx
hx buildBoth produce the same output.
Gradual Adoption
- Start with
hx init— no behavior change - Add
hx.lock— reproducible builds - Use hx commands — better UX
- Eventually, primary tool
Configuration Mapping
Package Options
-- cabal.project
package my-lib
ghc-options: -O2
flags: +feature# hx.toml (for common cases)
[build]
ghc-options = ["-O2"]Note: Keep complex package-specific options in cabal.project.
Source Repository Packages
Keep in cabal.project:
source-repository-package
type: git
location: https://github.com/user/package
tag: v1.0.0hx reads these automatically.
Allow-Newer
Keep in cabal.project:
allow-newer: some-package:baseCI Migration
Before (Cabal)
- run: cabal update
- run: cabal build
- run: cabal testAfter (hx)
- run: hx toolchain install
- run: hx lock --frozen
- run: hx build
- run: hx testBenefits
After migration:
- Lockfile — Reproducible builds
- Better errors — Clearer diagnostics
- Watch mode —
hx watch test - Integrated formatting —
hx fmt - Health checks —
hx doctor - Toolchain management —
hx toolchain install
Troubleshooting
Different Build Results
hx uses the same Cabal backend, so builds should be identical. If different:
- Check GHC versions match
- Check lockfile is synced:
hx sync - Clean and rebuild:
hx clean && hx build
Missing Dependencies
# Sync dependencies from lockfile
hx synccabal.project Settings Not Respected
hx respects cabal.project. Check:
# Verbose output shows what's being used
hx build --verboseSee Also
- hx init — Initialize hx
- Configuration — hx.toml reference
- Lockfiles — Reproducible builds