Nilla Nix Framework

repository·main·Indexed 41 days ago

https://github.com/nilla-nix/nilla

A modular Nix framework for project management that combines Flakes' schema guarantees with NixOS Modules' extensibility. It supports configurable inputs, custom loaders, multi-system support, and a dedicated CLI for streamlined development.

Tokens
2.5K
Snippets
7
Records
12
Agent score
1%

What's inside Nilla

  1. How Nilla modules and Aux Lib work

    main

    Nilla uses Aux Lib for its module system. When customizing your configuration or writing new modules, note these key differences from Nixpkgs:

    • Module Arguments: Always dynamic; do not use ....
    • Inclusion/Exclusion: Use includes to add modules and excludes to remove them (instead of imports or disabledModules).
    • Fallback Types: Use the freeform attribute to declare fallback types for dynamic values (instead of freeformType).
    • Option Creation: Use lib.options.create (instead of lib.mkOption).
    • Types: Types are namespaced, e.g., lib.types.attrs.any or lib.types.attrs.of.
    • Shorthand: Module shorthand is only available in submodules that explicitly opt-in.
  2. Create a Nilla Project

    main

    A Nilla project is defined by a nilla.nix file (typically at the project root) that uses nilla.create to define packages, shells, and system configurations.

    To start, create a nilla.nix file and import Nilla using builtins.fetchTarball.

    let
      nilla = import (builtins.fetchTarball {
        url = "https://github.com/nilla-nix/nilla/archive/main.tar.gz";
        sha256 = "0000000000000000000000000000000000000000000000000000";
      });
    in
    nilla.create {
        # You will add your project's configuration here!
    }
  3. Configure inputs and development shells in Nilla

    main

    Nilla allows you to define inputs (like nixpkgs) and shells.

    • Inputs: Each input can specify a src and a loader. The loader (e.g., nixpkgs) prepares the input for use. You can configure settings for the loader, such as specifying supported systems.
    • Shells: You can define development shells (e.g., shells.default). Shells are available on the platforms listed in their systems attribute. Shell definitions use the Nixpkgs callPackage convention by default, where the shell attribute is a function receiving dependencies.
    let
      nilla = import (builtins.fetchTarball {
        url = "https://github.com/nilla-nix/nilla/archive/main.tar.gz";
        sha256 = "0000000000000000000000000000000000000000000000000000";
      });
    in
    nilla.create {
      config = {
        inputs = {
          nixpkgs = {
            src = builtins.fetchTarball {
              url = "https://github.com/NixOS/nixpkgs/archive/nixos-unstable.tar.gz";
              sha256 = "0000000000000000000000000000000000000000000000000000";
            };
            loader = "nixpkgs";
            settings = {
                systems = [ "x86_64-linux" "aarch64-linux" ];
            };
          };
        };
    
        shells.default = {
          systems = [ "x86_64-linux" "aarch64-linux" ];
          shell = { mkShell, hello, ... }: 
            mkShell {
              packages = [ hello ];
            };
        };
      };
    }
  4. Configure Nilla builders

    main

    Builders are responsible for the build logic. You can define custom builders or use default ones by configuring:

    • builders.<name>.settings.type: The settings type used for validation and merging.
    • builders.<name>.settings.default: The default settings value (typically an empty attribute set).
    • builders.<name>.load: The loading function, which expects an object containing src, loader, and settings.
    {
      src: Derivation,
      loader: String,
      settings: LoaderSettings,
    }
  5. Configure Nilla packages

    main

    Packages in Nilla are defined by specifying which systems they target and which builder to use.

    Configuration keys for packages.<name>:

    • packages.<name>.systems: A list of target systems.
    • packages.<name>.builder: The builder name (defaults to "nixpkgs").
    • packages.<name>.settings: Additional settings passed to the builder.
    • packages.<name>.package: The function that defines the package and returns a derivation.

    Note: packages.<name>.result.<system> is a read-only location where Nilla automatically places the built package for each system.

  6. Configure Nilla inputs and loaders

    main

    Nilla allows you to define inputs that are processed by loaders. While Nilla attempts to auto-detect the appropriate loader based on source content, it is best practice to explicitly set the loader name.

    Key configuration keys for inputs include:

    • inputs.<name>.src: The source derivation (e.g., via fetchTarball).
    • inputs.<name>.loader: The name of the loader to use.
    • inputs.<name>.settings: Loader-specific settings.
    • inputs.<name>.result: The resulting loaded form of the input.

    You can also customize how loaders behave using loaders.<name>.settings.type and loaders.<name>.settings.default.

  7. Configure Nilla shells

    main

    Shells allow you to define development environments for specific systems.

    Configuration keys for shells.<name>:

    • shells.<name>.systems: A list of systems the shell is built for.
    • shells.<name>.builder: The builder name (defaults to "nixpkgs").
    • shells.<name>.settings: Additional settings passed to the builder.
    • shells.<name>.shell: The function that defines the shell and returns a derivation.

    Note: shells.<name>.result.<system> is a read-only location where Nilla automatically places the built shell for each system.

  8. Consume a custom Loader in a Nilla project

    main

    To use a custom loader, include the module in your nilla.create call via the includes attribute. You can then access the loaded data via config.inputs.<input-name>.result.

    # nilla.nix
    let
      nilla = import (builtins.fetchTarball {
        url = "https://github.com/nilla-nix/nilla/archive/main.tar.gz";
        sha256 = "0000000000000000000000000000000000000000000000000000";
      });
    in
    nilla.create ({ config }: 
      let
        text = config.inputs.myinput.result;
      in
      {
        includes = [ ./hello-loader.nix ];
    
        config = {
          inputs = {
            myinput = {
              src = ./my/input;
              loader = "hello";
            };
          };
        };
      })
  9. Create a custom Loader module

    main

    Loaders are responsible for preparing an input for project consumption. You can define a custom loader by adding a module to the config.loaders.<name> attribute. A loader typically defines settings (for configuration) and a load function that takes an input and returns the processed data.

    # hello-loader.nix
    { lib }: 
    {
      config.loaders.hello = {
        settings = {
          type = lib.types.attrs.any;
          default = {};
        };
    
        load = input: 
          let
            text = builtins.readFile "${input.src}/hello.txt";
          in
            text;
      };
    }
  10. Reference: Nilla default options and global keys

    main

    The following global and module-level options are provided by default in Nilla. You can disable any module's options using the excludes key in your project configuration.

    # Global/Module Keys
    nilla.version
    lib.*             # Customizable instance of Aux Lib for helper functions
    
    # Input Configuration
    inputs.<name>.src
    inputs.<name>.loader
    inputs.<name>.settings
    inputs.<name>.result
    
    # Loader Configuration
    loaders.<name>.settings.type
    loaders.<name>.settings.default
    loaders.<name>.load
    
    # Builder Configuration
    builders.<name>.settings.type
    builders.<name>.settings.default
    builders.<name>.build
    
    # Package Configuration
    packages.<name>.systems
    packages.<name>.builder
    packages.<name>.settings
    packages.<name>.package
    packages.<name>.result.<system>  # Read-only
    
    # Shell Configuration
    shells.<name>.systems
    shells.<name>.builder
    shells.<name>.settings
    shells.<name>.shell
    shells.<name>.result.<system>  # Read-only