(flakes-definition)=
# 플레이크

```{contributors}
:authors: kiara
```

## 플레이크란 무엇입니까?

플레이크는 Nix 코드를 공유하기 위한 진입점 파일 `flake.nix`를 제공합니다. 플레이크를 사용하면 같은 버전으로 프로그램을 쉽게 빌드할 수 있습니다.

`flake.nix`는 [표준 구조][standard structure]로 입력과 출력을 선언하는 파일입니다.

> 참고: [실험적][Experimental] 기능이며 [Nix 2.4]가 필요합니다.

이 파일은 다음과 같은 형태일 수 있습니다.

```nix
{
  description = "My example flake";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
  };

  outputs = { self, nixpkgs }: {
    packages.x86_64-linux = {
      default = self.packages.x86_64-linux.hello;
      hello = nixpkgs.legacyPackages.x86_64-linux.hello;
    };
  };
}
```

[`outputs`]에는 다양한 [기본 제공 유형][built-in types]이 포함되지만 [확장][extended]할 수도 있습니다. 이에 대한 개요는 [위키][wiki]에서 확인할 수 있습니다.

[`inputs`]로 의존성을 선언할 수 있습니다.

[`nix` 명령][`nix` command]을 실행하면 Nix는 의존성을 고정하기 위해 [`flake.lock`]을 생성합니다.

이 의존성에 자체 `inputs`가 있으면 Nix는 사용할 버전을 찾기 위해 _해당 의존성의_ lock 파일을 확인합니다. 같은 버전을 사용하면 프로그램이 의도한 대로 동작하는 데 도움이 되지만, 이를 오버라이드할 수도 있습니다.

[`nix` 명령][`nix` command]은 기본적으로 플레이크와 네이티브하게 통합됩니다.

```bash
nix build github:NixOS/nixpkgs#hello
```

로컬(예: `.`) 또는 원격(예: `github:NixOS/nixpkgs`) 프로젝트 디렉터리에 대한 [참조][references]를 전달할 수 있습니다. 자세한 내용은 [`nix` 명령][`nix` command]에 대한 참조 문서를 확인하십시오.

플레이크의 별칭은 [레지스트리][registry]에 저장됩니다. 레지스트리는 [명령줄][command-line]이나 {term}`NixOS` 옵션 [`nix.registry`]로 확장할 수 있습니다.

[^subset]: 플레이크는 기본적으로 순수 모드로 동작하며, 빌드를 호스트 환경으로부터 격리합니다. 이를 밀폐 평가(hermetic evaluation)라고도 하며, 이 모드에서는 (네트워크를 사용하지 않는) [impure] 함수를 평가할 수 없습니다. 플레이크의 `inputs`와 메타데이터 필드에는 임의의 Nix 표현식을 사용할 수 없습니다. 이는 복잡하거나 종료되지 않을 수 있는 계산을 막기 위함입니다. `outputs` 필드의 함수 매개변수는 반드시 명시해야 합니다. [에타 축약][eta-reduction]을 지원하지 않기 때문입니다.

[플레이크 기반 설치][flake-based installs]에 대한 자세한 설명은 NixOS 매뉴얼에 있습니다.

[Experimental]: https://nix.dev/manual/nix/stable/development/experimental-features#xp-feature-flakes
[Nix 2.4]: https://nix.dev/manual/nix/stable/release-notes/rl-2.4.html#highlights
[standard structure]: https://nix.dev/manual/nix/stable/command-ref/new-cli/nix3-flake.html#flake-format
[`nix` command]: https://nix.dev/manual/nix/stable/command-ref/new-cli/nix.html
[references]: https://nix.dev/manual/nix/stable/command-ref/new-cli/nix3-flake#flake-references
[`outputs`]: https://wiki.nixos.org/wiki/Flakes#Output_schema
[built-in types]: https://github.com/NixOS/nix/blob/38c755f168b7c38cd4687aacf5d7e59f049658d3/src/nix/flake.cc#L594-L769
[extended]: https://github.com/NixOS/nix/blob/38c755f168b7c38cd4687aacf5d7e59f049658d3/src/nix/flake.cc#L772-L776
[wiki]: https://wiki.nixos.org/wiki/Flakes#Output_schema
[`inputs`]: https://nix.dev/manual/nix/stable/command-ref/new-cli/nix3-flake.html#flake-inputs
[`flake.lock`]: https://nix.dev/manual/nix/stable/command-ref/new-cli/nix3-flake.html#lock-files
[impurities]: https://nix.dev/manual/nix/stable/tutorials/nix-language.html#impurities
[registry]: https://github.com/NixOS/flake-registry
[command-line]: https://nix.dev/manual/nix/2.28/command-ref/new-cli/nix3-registry.html
[`nix.registry`]: https://search.nixos.org/options?channel=unstable&show=nix.registry&query=registry
[eta-reduction]: https://wiki.haskell.org/Eta_conversion
[flake-based installs]: https://nixos.org/manual/nixos/stable/#sec-installation-manual-installing

## 제 프로젝트에서 플레이크를 사용해야 합니까?

플레이크는 아직 해결되지 않은 문제가 남아 있는 실험적 확장 형식입니다. 플레이크가 제공하는 기능은 대체로 플레이크 없이도 구현할 수 있습니다.

이미 플레이크를 사용하는 기존 소프트웨어를 실행해야 하거나 플레이크 개발에 기여하고 싶다면 자유롭게 사용하십시오. Nix 코드를 직접 작성하려면 [의존성 관리][dependency management]에 관한 가이드도 참고하십시오.[^flake-inputs] 이 개요는 호환성을 유지하면서 플레이크에서 필요한 것(입력 등)을 얻는 데 도움이 됩니다.

[dependency management]: https://nix.dev/guides/recipes/dependency-management.html

[^flake-inputs]: 플레이크 진입점만 제공하는 Nix 저장소는 [`flake-inputs`]를 사용하여 가져올 수 있습니다.

### 발견 가능성

플레이크를 사용하는 첫 단계는 `outputs`를 지정하는 `flake.nix` 파일을 추가하는 것입니다.

장점:

- 다른 플레이크 프로젝트의 코드를 사용할 수 있습니다.
- Nix가 `flake.nix`의 구조가 유효한지 검사합니다.

단점:

- 플레이크에는 [매개변수][parameters]가 없습니다. 따라서 `flake.nix`와 그 최종 사용자는 사용하는 [`system`]을 명시해야 합니다. 예를 들어 [`flake-utils`]를 사용하면 이 작업이 더 쉬워집니다.
- 플레이크는 실험적 기능이므로 아직 바뀔 수 있습니다.

[parameters]: https://github.com/NixOS/nix/issues/2861
[`system`]: https://github.com/NixOS/nix/issues/3843
[`flake-utils`]: https://github.com/numtide/flake-utils

대안:

- 플레이크를 기존 Nix 코드를 감싸는 얇은 래퍼로 사용하십시오. 이렇게 하면 코드를 두 가지 방식 모두로 사용할 수 있습니다.
- Nix 모듈을 사용하십시오. 플레이크 사용자는 `flake = false;`로 이를 가져올 수 있습니다.
- NixOS 26.05부터는 단일 [`system.nix` 진입점][`system.nix` entrypoint]에서 하나 이상의 NixOS 설정을 불러올 수 있습니다.

[`import`]: https://nix.dev/tutorials/nix-language#import
[`system.nix` entrypoint]: https://nixos.org/manual/nixos/stable/release-notes.html#sec-release-26.05-highlights

### 명령 실행하기

플레이크는 Nix의 [v3 `nix` 명령줄 인터페이스][v3 `nix` command line interface]에서 사용합니다. 이 인터페이스는 `.`이나 `github:NixOS/nixpkgs` 같은 참조로 프로그램을 빌드하거나 실행할 수 있습니다.

다음을 추가하여 명령 하나에 대해서만 이를 활성화할 수 있습니다:

```
 --experimental-features 'nix-command flakes'
````

또는 NixOS나 Home Manager 설정에서 다음을 사용하여 영구적으로 활성화할 수 있습니다:

```
nix.settings.experimental-features = [ "nix-command" "flakes" ];
```

`flake.nix`의 `packages.x86_64-linux.default`에 있는 derivation을 빌드하려면 다음을 실행하십시오:

```bash
nix build .#packages.x86_64-linux.default
```

이를 `nix build .#default` 또는 그냥 `nix build`로 줄일 수 있습니다.

`nix run`은 `outputs.apps`에 있는 프로그램을 실행합니다. `nix run .#default`는 `outputs.apps.default`를 실행합니다. 그냥 `nix run`만 입력해도 같은 것을 실행합니다.

예를 들어 {term}`Nixpkgs`의 `hello` 패키지를 실행하려면 다음과 같이 하십시오:

```bash
nix run nixpkgs#hello -- --greeting "hello from flakes"
```

이는 레지스트리의 별칭 `nixpkgs`에 설정된 버전을 사용합니다.

{term}`Nixpkgs`의 `nixpkgs-unstable` 브랜치에서 `hello` 패키지를 실행하려면 다음과 같이 하십시오:

```bash
nix run github:NixOS/nixpkgs/nixpkgs-unstable#hello
```

[v3 `nix` command line interface]: https://nix.dev/manual/nix/stable/command-ref/new-cli/nix.html

장점:

- 플레이크는 빌드를 캐시하여 이후의 동일한 빌드에 드는 시간을 절약합니다. 예를 들어 지속적 통합(Continuous Integration)에서 변경되지 않은 빌드를 실행할 때 시간을 절약할 수 있습니다.
- 플레이크는 원격 저장소에 있는 프로그램까지도 쉽게 실행할 수 있도록 장려합니다.
- 플레이크는 기본적으로 [순수 모드][pure mode]로 실행됩니다. 이는 프로그램을 재현 가능하게 만들 가능성이 더 높은 작성 방식을 장려합니다[^reproducible].
- [Git]을 사용하는 프로젝트에서 플레이크는 추적되는 파일만 빌드합니다. 이는 불필요한 재빌드를 막는 데 도움이 됩니다.

[pure mode]: https://nix.dev/manual/nix/stable/tutorials/nix-language.html#impurities

[^reproducible]: 순수 모드에서도 재현성이 [실제로 보장되지는 않습니다][not actually guaranteed].

[not actually guaranteed]: https://discourse.nixos.org/t/nix-flakes-explained-what-they-solve-why-they-matter-and-the-future/72302/7

단점:

- 빌드할 때 플레이크 디렉터리 전체를 Nix 스토어로 복사합니다. 이렇게 하면 캐시되지만, {term}`Nixpkgs`와 같은 대규모 저장소에서는 [더 느려질][slower] 수 있습니다.
- 구현에는 [플레이크][flakes]와 [v3 CLI] 모두에 여전히 문제가 있습니다.
- 플레이크가 파일을 인식하려면 파일이 스테이징되어 있어야 합니다.

[slower]: https://github.com/NixOS/nix/issues/3121
[flakes]: https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+label%3Aflakes+sort%3Areactions-%2B1-desc
[v3 CLI]: https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+label%3Anew-cli+sort%3Areactions-%2B1-desc

대안:

- 일반 Nix 파일은 [v2 commands]([`nix-build`], [`nix-shell`] 등)와 함께 사용하거나, v3 명령의 [`--file` 플래그][`--file` flag] 또는 `-f`와 함께 사용할 수 있습니다.
- {term}`NixOS`에서는 NixOS 설정에 [`nixpkgs.flake.source = pkgs.path;`]를 지정하여 v3 명령의 `nixpkgs`가 패키지 집합 `pkgs`를 가리키도록 할 수 있습니다. [의존성 관리][managing dependencies]도 참고하십시오.
- 실험적 기능 [`fetch-tree`]의 [`builtins.fetchTree`]를 사용하면 플레이크가 아닌 진입점에 대해 [`nix run`]을 에뮬레이션할 수 있습니다[^emulated].

[Git]: https://git-scm.com/
[v2 CLI]: https://nix.dev/manual/nix/stable/command-ref/main-commands
[`--file` flag]: https://nix.dev/manual/nix/stable/command-ref/new-cli/nix3-build.html#options-that-change-the-interpretation-of-installables
[`nix-build`]: https://nix.dev/manual/nix/stable/command-ref/nix-build.html
[`nix-shell`]: https://nix.dev/manual/nix/stable/command-ref/nix-shell.html
[`nixpkgs.flake.source = pkgs.path;`]: https://search.nixos.org/options?channel=unstable&show=nixpkgs.flake.source&query=nixpkgs.flake.source
[managing dependencies]: https://nix.dev/guides/recipes/dependency-management#managing-nixos-configurations
[`builtins.fetchTree`]: https://noogle.dev/f/builtins/fetchTree
[`fetch-tree`]: https://nix.dev/manual/nix/stable/development/experimental-features#xp-feature-fetch-tree
[`nix run`]: https://nix.dev/manual/nix/stable/command-ref/new-cli/nix3-run.html

[^emulated]: 플레이크가 아닌 프로젝트에서 `nix run github:NixOS/nixpkgs#hello`는 `nix-shell -p '(import (builtins.fetchTree "github:NixOS/nixpkgs").outPath { }).hello' --run 'hello'`와 같은 형태가 될 수 있습니다. `nix run` 구문을 사용하는 대체 명령 `nix-run`은 `alias nix-run='run() { $(nix-instantiate --raw --impure --eval --expr "(import <nixpkgs> {}).lib.getExe (import (builtins.fetchTree \"$(cut -d "#" -f 1 <<< "$1")\").outPath { }).$(cut -d "#" -f 2 <<< "$1")"); }; run'`와 같은 Bash 별칭으로 정의할 수 있습니다.

### 의존성 관리

플레이크의 `inputs` 속성으로 의존성을 관리할 수 있습니다. 기본적으로 재귀적 의존성은 암묵적으로 처리됩니다. 하나의 라이브러리가 여러 번 사용되는 경우, 같은 라이브러리의 서로 다른 버전이 사용될 수 있습니다. 원한다면 `follows` 문을 사용하여 이를 오버라이드할 수 있습니다:

```
{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
    home-manager = {
      url = "github:nix-community/home-manager";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };
}
```

이렇게 하면 Home Manager의 입력이 사용자가 선택한 `nixpkgs`를 재사용합니다.

장점:

- 공개된 소프트웨어를 그 소프트웨어가 사용한 버전 그대로 쉽게 재현할 수 있습니다.
- 재귀적 입력을 오버라이드할 수 있습니다.

단점:

- 플레이크는 기본적으로 의존성의 `flake.lock`에 있는 버전을 따르므로, `follows`로 이를 오버라이드하지 않으면 다음과 같은 문제가 생길 수 있습니다:
  - 같은 의존성의 여러 버전.
  - 버전이 활발히 업데이트되지 않는 경우, 오래된 의존성.
- 의존성을 즉시 가져오므로 사용하지 않을 수도 있는 의존성까지 불러옵니다.
- 플레이크 입력으로 관리되는 의존성은 플레이크를 함께 사용하지 않으면 오버라이드하기 어렵습니다.
- 플레이크가 라이브러리로 사용된다면 모든 재귀적 입력에 대해 `follows` 문을 추가해야 합니다. 그렇지 않으면 다운스트림 사용자가 간접 입력에 자신의 `follows`를 추가할 수 없습니다.

대안:

- [`npins`]로 의존성을 관리하십시오.
- [페처][fetchers]나 [`builtins.fetchTree`] 같은 함수를 사용하여 의존성을 인라인으로 관리하십시오.
- `inputs.<name>.flake = false;`를 사용하십시오.

[fetchers]: https://nixos.org/manual/nixpkgs/stable/#chap-pkgs-fetchers
[`flake-inputs`]: https://github.com/fricklerhandwerk/flake-inputs
[`npins`]: https://nix.dev/guides/recipes/dependency-management.html

### 플레이크 전용 Nix

플레이크는 (대체로[^subset]) Nix를 내부 언어로 사용하므로 모든 Nix 코드를 플레이크 파일에 넣을 수도 있습니다. 커뮤니티에서는 이러한 코딩 스타일을 덴드리틱 패턴(dendritic pattern)이라고 부릅니다. 플레이크를 사용하면 [`flake-parts`](https://github.com/hercules-ci/flake-parts) 라이브러리로 이 패턴을 더 쉽게 적용할 수 있습니다. 이 라이브러리를 사용하면 코드를 플레이크와 비슷한 여러 파일에 나누어 둘 수 있습니다.

장점:

- 이러한 Nix 코드 어디에서나 플레이크의 스키마와 입력을 사용하기 쉬워집니다.

단점:

- 플레이크를 사용하지 않고는 이 코드에 접근하기가 더 어려워집니다.

대안:

- 플레이크를 기존 Nix 코드를 감싸는 얇은 래퍼로 사용하여 코드를 두 가지 방식 모두로 사용할 수 있게 하십시오.
- [`flake-compat`] 라이브러리를 사용하여 플레이크의 기본 패키지나 셸을 플레이크를 사용하지 않는 사용자에게 노출하십시오.
- 필요한 매개변수를 명시적으로 전달하거나 NixOS의 [`specialArgs`]를 사용하여 모듈 간에 전파하십시오.

[`flake-compat`]: https://github.com/NixOS/flake-compat
[`specialArgs`]: https://nixos.org/manual/nixos/unstable/options#opt-_module.args

### 역사

- 구상
  - 플레이크는 [RFC 49]에서 제안되었고 [블로그 게시물][blog post]을 통해 소개되었습니다.
- 설계
  - 플레이크 제안은 너무 많은 문제를 한꺼번에, 그것도 잘못된 추상화 계층에서 해결하려 한다는 비판을 받았습니다.
  - 이 설계에는 버전 관리, 조합성, 교차 컴파일, nixpkgs와의 강한 결합 등을 비롯한 [여러 문제][various problems]가 여전히 남아 있습니다.
  - `nix` CLI를 둘러싼 [미해결 설계 문제][open design questions]도 여전히 많습니다.
- 구현
  - [구현상의 문제][problems with the implementation]도 여전히 남아 있습니다.
- 절차
  - 설계에 대한 우려가 아직 해소되지 않은 상태에서 RFC가 승인되지 않은 채로(실제로는 병합 시점에 철회됨) 구현이 병합되었고, 이로 인해 절차가 적절했는지에 대한 의문이 제기되었습니다.
  - 해당 RFC는 실험을 마무리할 일정 없이 종료되었습니다.
  - 많은 프로젝트가 플레이크에 의존하게 되면서, 많은 사람의 코드를 깨뜨리지 않고 설계를 반복적으로 개선하기가 더 어려워졌습니다.
- 커뮤니티
  - 이 설계는 커뮤니티 전체에서 받아들여지지는 않았으며, 예를 들어 {term}`Nixpkgs`는 내부 도구에서 이를 사용하지 않았습니다. 그 결과 플레이크에 대한 접근 방식이 여러 갈래로 나뉘었습니다. 예를 들어 Determinate Systems사(플레이크와 관련된 독점 기능을 제공하는 회사)는 이 기능을 일방적으로 안정 기능이라고 선언했고, 커뮤니티 주도의 Nix 포크인 Lix는 사실상의 'v1'으로 [기능 집합을 통합했습니다][consolidated the featureset]. 이러한 분화는 애초에 플레이크 실험을 추진하게 한 통합 인터페이스라는 약속을 결국 깨뜨릴 수도 있습니다.

[RFC 49]: https://github.com/NixOS/rfcs/pull/49
[blog post]: https://tweag.io/blog/2020-05-25-flakes/
[various problems]: https://wiki.lix.systems/books/lix-contributors/page/flakes-feature-freeze#bkmrk-design-issues-of-fla
[open design questions]: https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+label%3Anew-cli+sort%3Areactions-%2B1-desc
[problems with the implementation]: https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+label%3Aflakes+sort%3Areactions-%2B1-desc
[consolidated the featureset]: https://wiki.lix.systems/books/lix-contributors/page/flake-stabilisation-proposal

## 더 읽을거리

- [위키 문서](https://wiki.nixos.org/wiki/Flakes)
- [플레이크는 실재하지 않으며 여러분을 해칠 수 없습니다: 플레이크가 아닌 방식으로 Nix 플레이크를 사용하는 가이드](https://jade.fyi/blog/flakes-arent-real/) (Jade Lovelace, 2024년 1월)
- [Nix 플레이크는 한꺼번에 너무 많은 것을 시도한 실험입니다...](https://samuel.dionne-riel.com/blog/2023/09/06/flakes-is-an-experiment-that-did-too-much-at-once.html) ([댓글](https://discourse.nixos.org/t/nix-flakes-is-an-experiment-that-did-too-much-at-once/32707)) (Samuel Dionne-Riel, 2023년 9월)
- [실험적이라는 것이 불안정하다는 뜻은 아닙니다](https://determinate.systems/posts/experimental-does-not-mean-unstable) ([댓글](https://discourse.nixos.org/t/experimental-does-not-mean-unstable-detsyss-perspective-on-nix-flakes/32703)) (Graham Christensen, 2023년 9월)
- [The Nix Hour: 플레이크와 기존 Nix 비교](https://www.youtube.com/watch?v=atmoYyBAhF4) (Silvan Mosberger, 2022년 11월)
