core/docs/concepts.md

76 lines
2.9 KiB
Markdown
Raw Normal View History

2025-12-20 21:27:10 +01:00
# Concepts
Rensa is built around a few core concepts that help structure your Nix projects.
## Cells
A **Cell** is the fundamental unit of organization in Rensa.
It represents a functional domain or a component of your system.
For example, you might have cells for:
- `backend`: Your backend services.
- `frontend`: Your frontend applications.
Cells are directories located in the `cellsFrom` directory (usually `cells/` or `nix/`).
### Cell Flakes
A unique feature of Rensa is that each cell can be a self-contained Flake.
If a cell directory contains a `flake.nix`, Rensa will treat it as a flake and pass its outputs to the cell's blocks.
This allows you to manage dependencies at the cell level, keeping your top-level `flake.nix` clean.
!!! success "Advantage"
These nested flakes are also evaluated lazily, so inputs are only fetched if they are actually used.
## Blocks
A **Block** defines a specific type of output within a cell. Blocks are typically defined as `.nix` files within a cell directory.
Rensa provides different block types to handle various use cases.
### Simple Blocks
`rensa.blocks.simple` is the most common block type.
Use it to tell Rensa which blocks you have/it should load.
**Example**:
```nix
blocks = with ren.blocks; [
(simple "hello")
]
```
This will tell Rensa to load any `hello.nix` or `hello/default.nix` in the cells.
It's required to be able to map these to flake outputs (eg. using `ren.select`).
### Dynamic Blocks
`rensa.blocks.dynamic` allows for more complex logic and can generate actions.
## Actions
**Actions** are commands that can be executed via the Std CLI.
They are defined within blocks and allow you to operationalize your Nix code.
For example, a `deploy` action in an `infra` cell could run the necessary commands to deploy your infrastructure.
!!! warning
Actions are also heavily inspired by Std, I added them to Rensa too, but nowadays
I don't see any real use cases for them. If you do, feel free to use and/or extend them :)
## Performance & Best Practices
### Single Instantiation of Nixpkgs
Instantiating `nixpkgs` (e.g., `import inputs.nixpkgs { inherit system; }`) is a computationally expensive operation. In a large project with many cells, doing this repeatedly for every cell or block can significantly slow down evaluation.
The recommended pattern in Rensa is to instantiate `nixpkgs` **once** in your top-level `flake.nix` and pass it down to your cells.
1. **Instantiate in `transformInputs`**: In your `flake.nix`, use the `transformInputs` argument of `buildWith` to add the instantiated `pkgs` to the inputs passed to cells.
1. **Use `i.parent.pkgs`**: In your cell flakes, access this pre-instantiated package set via `inputs.parent.pkgs`.
This ensures that `nixpkgs` is evaluated only once per system, drastically improving performance.
See [Related Libraries](./libraries.md) for examples of this pattern.