Migration Guide
Migration Guide
Section titled “Migration Guide”This guide helps migrate code from legacy Ghaf patterns to the modern composition-based architecture.
Overview of Changes
Section titled “Overview of Changes”The Ghaf architecture has been significantly refactored to improve composability and maintainability:
| Aspect | Legacy Pattern | Modern Pattern |
|---|---|---|
| Host-VM communication | configHost = config; | globalConfig + hostConfig via specialArgs |
| VM customization | extraModules option | extendModules on VM bases |
| Settings propagation | Manual threading | specialArgs injection |
| Feature assignment | Hardcoded in VMs | globalConfig.features with targetVms |
| Profile selection | Debug flag checks | lib.ghaf.profiles.* |
Migration Path
Section titled “Migration Path”Step 1: Update Module Arguments
Section titled “Step 1: Update Module Arguments”Legacy:
{ configHost }:let cfg = configHost.ghaf.virtualization.microvm.guivm;in{ config = { ghaf.profiles.debug.enable = configHost.ghaf.profiles.debug.enable; };}Modern:
{ config, lib, globalConfig, hostConfig, ... }:{ _file = ./my-module.nix;
config = { ghaf.profiles.debug.enable = globalConfig.debug.enable; networking.hostName = hostConfig.vmName; };}Step 2: Update VM Base Modules
Section titled “Step 2: Update VM Base Modules”Legacy:
# Inline in guivm.nixguivmBaseConfiguration = { imports = [ ... ]; config = { ghaf.profiles.debug.enable = configHost.ghaf.profiles.debug.enable; networking.hostName = "gui-vm"; # ... hundreds of lines of config };};
microvm.vms.gui-vm.config = guivmBaseConfiguration // { imports = guivmBaseConfiguration.imports ++ cfg.extraModules;};Modern:
# In guivm-base.nix (separate file){ globalConfig, hostConfig, ... }:{ _file = ./guivm-base.nix;
ghaf.profiles.debug.enable = globalConfig.debug.enable; networking.hostName = hostConfig.vmName; # ... config with specialArgs access}
# In profile (laptop-x86.nix)guivmBase = lib.nixosSystem { specialArgs = lib.ghaf.vm.mkSpecialArgs { inherit lib inputs; globalConfig = config.ghaf.global-config; hostConfig = lib.ghaf.vm.mkHostConfig { inherit config; vmName = "gui-vm"; }; }; modules = [ guivm-base hardwareExtras ];};
# In guivm.nix - wire up using evaluatedConfigconfig = lib.mkIf cfg.enable { microvm.vms.gui-vm.evaluatedConfig = cfg.evaluatedConfig;};Step 3: Update extraModules Usage
Section titled “Step 3: Update extraModules Usage”Legacy:
# In modules.nixghaf.virtualization.microvm.guivm.extraModules = [ firmwareModule servicesModule desktopModule];
# In targetghaf.virtualization.microvm.guivm.extraModules = lib.mkAfter [ myCustomModule];Modern:
# In profile - compose base with hardware modulesguivmBase = lib.nixosSystem { specialArgs = ...; modules = [ guivm-base hardware.definition.guivm.extraModules # Feature modules auto-included via imports ];};
# In target - use extendModuleslet baseVm = config.ghaf.profiles.laptop-x86.guivmBase; extendedVm = baseVm.extendModules { modules = [ myCustomModule ]; };in{ # Pass the full system result, not .config ghaf.virtualization.microvm.guivm.evaluatedConfig = extendedVm;}Step 4: Update Feature Configuration
Section titled “Step 4: Update Feature Configuration”Legacy:
# Hardcoded in guivm-base.nixservices.fprintd.enable = true;
# Or with optionservices.fprintd.enable = cfg.features.fprint.enable;Modern:
# In global configghaf.global-config.features.fprint = { enable = true; targetVms = [ "gui-vm" ];};
# In VM baseservices.fprintd.enable = lib.ghaf.features.isEnabledFor globalConfig "fprint" "gui-vm";Step 5: Update Profile Selection
Section titled “Step 5: Update Profile Selection”Legacy:
# In target{ ... }:let variant = "debug";in{ # Manual debug/release logic everywhere ghaf.profiles.debug.enable = variant == "debug"; ghaf.development.ssh.daemon.enable = variant == "debug"; # ... repeated for every option}Modern:
# In target - use variant parametermkGhafConfiguration { name = "my-target"; system = "x86_64-linux"; profile = "laptop-x86"; hardwareModule = self.nixosModules.hardware-my-target; variant = "debug"; # Auto-applies lib.ghaf.profiles.debug via mkDefault}
# Or with customization via extraConfigmkGhafConfiguration { # ... params ... variant = "debug"; extraConfig = { global-config.features.bluetooth.enable = false; };};Common Migration Patterns
Section titled “Common Migration Patterns”Pattern: Threading Inputs
Section titled “Pattern: Threading Inputs”Legacy (Anti-pattern):
{ inputs }:{ imports = [ (import ./module-b.nix { inherit inputs; }) ];}
# module-b.nix{ inputs }:{ config = { something = inputs.self.packages.x86_64-linux.foo; };}Modern:
# In evaluation (profile or target)lib.nixosSystem { specialArgs = { inherit inputs lib; }; modules = [ ./module-a.nix ./module-b.nix ];}
# In module-b.nix{ inputs, ... }: # Available from specialArgs{ config.something = inputs.self.packages.x86_64-linux.foo;}Pattern: Accessing Host Config in VM
Section titled “Pattern: Accessing Host Config in VM”Legacy:
# VM module{ configHost }:{ services.foo.hostAddress = configHost.ghaf.common.extraNetworking.hostAddress; services.foo.debug = configHost.ghaf.profiles.debug.enable;}Modern:
# VM module{ globalConfig, hostConfig, ... }:{ services.foo.hostAddress = hostConfig.networking.hostAddress; services.foo.debug = globalConfig.debug.enable;}Pattern: Conditional VM Features
Section titled “Pattern: Conditional VM Features”Legacy:
# In modules.nixoptions.ghaf.virtualization.microvm.guivm.features.fprint.enable = ...;
# In guivm.nixservices.fprintd.enable = cfg.features.fprint.enable;
# In profileghaf.virtualization.microvm.guivm.features.fprint.enable = true;Modern:
# In lib/global-config.nixfeatures.fprint = { enable = mkEnableOption "fingerprint" // { default = true; }; targetVms = mkOption { default = [ "gui-vm" ]; };};
# In guivm-base.nixservices.fprintd.enable = lib.ghaf.features.isEnabledFor globalConfig "fprint" "gui-vm";
# In target (to customize)ghaf.global-config.features.fprint.targetVms = [ "admin-vm" ];Downstream Project Migration
Section titled “Downstream Project Migration”Before (Legacy Downstream)
Section titled “Before (Legacy Downstream)”{ outputs = { ghaf, ... }: let laptop-configuration = ghaf.builders.laptop-configuration; in { nixosConfigurations.my-product = laptop-configuration "lenovo-x1" "debug" [ ./hardware.nix ({ config, ... }: { # Customize via extraModules option ghaf.virtualization.microvm.guivm.extraModules = [ ./my-gui-customizations.nix ]; }) ]; };}After (Modern Downstream)
Section titled “After (Modern Downstream)”{ outputs = { ghaf, ... }: let mkGhafConfiguration = ghaf.lib.ghaf.builders.mkGhafConfiguration; in { nixosConfigurations.my-product-debug = mkGhafConfiguration { name = "my-product"; system = "x86_64-linux"; profile = "laptop-x86"; hardwareModule = ghaf.nixosModules.hardware-lenovo-x1-carbon-gen11; variant = "debug"; extraModules = [ ({ config, ... }: let baseVm = config.ghaf.profiles.laptop-x86.guivmBase; extendedVm = baseVm.extendModules { modules = [ ./my-gui-customizations.nix ]; }; in { # Pass the full system result, not .config ghaf.virtualization.microvm.guivm.evaluatedConfig = extendedVm; }) ]; }; };}Module Migration Checklist
Section titled “Module Migration Checklist”For each module you’re migrating:
- Add
_file = ./module-name.nix;as first attribute - Replace
{ configHost }:with{ config, lib, globalConfig, hostConfig, ... }: - Replace
configHost.ghaf.profiles.debug.enablewithglobalConfig.debug.enable - Replace hardcoded VM names with
hostConfig.vmName - Replace
configHost.ghaf.common.extraNetworking.*withhostConfig.networking.* - Replace feature checks with
lib.ghaf.features.isEnabledFor - Remove
{ inputs }:wrapper if present (use specialArgs instead) - Add proper imports from inputs
- Use
lib.mkDefaultfor overridable values - Test build with
nix build .#target --dry-run
Breaking Changes Reference
Section titled “Breaking Changes Reference”Removed Options
Section titled “Removed Options”| Removed | Replacement |
|---|---|
ghaf.virtualization.microvm.*.extraModules | Use extendModules on VM base |
modules.nix feature options | globalConfig.features.* |
lib.ghaf.mkVmSpecialArgs | lib.ghaf.vm.mkSpecialArgs |
lib.ghaf.mkVmHostConfig | lib.ghaf.vm.mkHostConfig |
lib.ghaf.getVmConfig | lib.ghaf.vm.getConfig |
Changed Behavior
Section titled “Changed Behavior”| Change | Impact |
|---|---|
VMs require evaluatedConfig | Must set via profile or extendModules |
| Features centralized | Move feature config to globalConfig.features |
| Profiles simplified | Use lib.ghaf.profiles.* for common presets |
Getting Help
Section titled “Getting Help”If you encounter issues migrating:
- Check the Architecture Documentation
- Review Anti-Patterns for common mistakes
- Look at existing modules for examples
- Open an issue on GitHub with specific error messages
See Also
Section titled “See Also”- Downstream Setup - New project setup
- Writing Modules - Module conventions
- Config Propagation - globalConfig/hostConfig
- VM Composition - extendModules pattern