{"id":13569542,"url":"https://github.com/xtruder/nix-devcontainer","last_synced_at":"2025-10-06T22:54:40.076Z","repository":{"id":37523705,"uuid":"296576399","full_name":"xtruder/nix-devcontainer","owner":"xtruder","description":"Swiss army knife container for vscode development environments","archived":false,"fork":false,"pushed_at":"2025-05-15T05:46:31.000Z","size":74,"stargazers_count":269,"open_issues_count":5,"forks_count":32,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-05-19T21:06:33.262Z","etag":null,"topics":["devcontainer","development","development-environment","direnv","docker","nix","vscode"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xtruder.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-09-18T09:30:40.000Z","updated_at":"2025-05-19T11:32:47.000Z","dependencies_parsed_at":"2025-05-19T21:06:40.682Z","dependency_job_id":"f637379b-0a34-476f-8c90-0ee6023f8d6e","html_url":"https://github.com/xtruder/nix-devcontainer","commit_stats":{"total_commits":68,"total_committers":4,"mean_commits":17.0,"dds":0.07352941176470584,"last_synced_commit":"42d11ec3fdac6cda5342b4dc83adbcb54d587038"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/xtruder/nix-devcontainer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xtruder%2Fnix-devcontainer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xtruder%2Fnix-devcontainer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xtruder%2Fnix-devcontainer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xtruder%2Fnix-devcontainer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xtruder","download_url":"https://codeload.github.com/xtruder/nix-devcontainer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xtruder%2Fnix-devcontainer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278692916,"owners_count":26029405,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-06T02:00:05.630Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["devcontainer","development","development-environment","direnv","docker","nix","vscode"],"created_at":"2024-08-01T14:00:41.214Z","updated_at":"2025-10-06T22:54:40.060Z","avatar_url":"https://github.com/xtruder.png","language":"Go","readme":"# nix-devcontainer\n\n![workflow status](https://github.com/xtruder/nix-devcontainer/actions//workflows/ci.yml/badge.svg)\n\n\n## Summary\n\n**Swiss army knife container for vscode development environments**\n\n| Metadata                    | Value                                                                         |\n| --------------------------- | ----------------------------------------------------------------------------- |\n| *Image*                     | [ghcr.io/xtruder/nix-devcontainer](https://github.com/xtruder/nix-devcontainer/pkgs/container/nix-devcontainer) |\n| *Image tags*                | v1,latest,edge                                                                |\n| *Definition type*           | standalone or Docker Compose                                                  |\n| *Works in Codespaces*       | Yes                                                                           |\n| *Container host OS support* | Linux, macOS, Windows                                                         |\n| *Languages, platforms*      | All languages that nix supports                                               |\n| *Contributors*              | [@offlinehacker](github.com/offlinehacker), [@Rizary](github.com/rizary)      |\n| *Maintainer*                | Jaka Hudoklin \u003cjaka@x-truder.net\u003e [@offlinehacker](github.com/offlinehacker)  |\n\n## Description\n\nNix devcontainer is an opinionated [vscode devcontainer](https://code.visualstudio.com/docs/remote/containers)\nthat uses debian image for a base system and [nix package manager](https://nixos.org/)\nfor management of your development environments. Combination\nof a good base image and a best in class package manager, gives\nyou versatile, reproduible and deterministic development environment\nthat you can use everywhere.\n\n### Components\n\n- **[Debian slim](https://hub.docker.com/_/debian) docker image**\n\n   Docker base image, which provides minimalistic environment in which both nix and\n   vscode remote extension can run without any issues.\n\n- **[Nix package manager](https://nixos.org/)**\n\n  Used for providing declarative, deterministic and reporoducible development environment that\n  you can run anywhere. Imagine better [conda](https://docs.conda.io/en/latest/) alternative.\n  You write a single `shell.nix` file that describes your environment and all your tools and\n  vscode extensions will be running with same exact versions of binaries, same environment\n  variables, same libraries forever.\n\n- **[Nix Environment Selector](https://marketplace.visualstudio.com/items?itemName=arrterian.nix-env-selector) vscode extension**\n\n   Used to automatically load nix development environment into your vscode and provides\n   capabilities to reload it later when environment changes, without having to rebuild\n   docker image from scratch on every change.\n\n- **[Direnv](https://direnv.net/) shell environment loader**\n\n   While nix environment loader extension loads environment for vscode, you\n   want `direnv` to manage you shell environment. `Direnv` loads nix environment\n   (defined by `shell.nix` file) into your shell and reloads it automatically when it changes,\n   keeping your environment fresh.\n\n## Example templates\n\nThere are sevaral example templates you can use to quickly bootstrap your project:\n\n- [nix-devcontainer-golang](https://github.com/xtruder/nix-devcontainer-golang/)\n  \n  Example project using `nix-devcontainer` for golang development, with docker-compose\n  running docker-in-docker service for building docker images.\n\n- [nix-devcontainer-python-jupyter](https://github.com/xtruder/nix-devcontainer-python-jupyter/)\n  \n  Example project using `nix-devcontainer` for python and jupyter notebooks,\n  with python packages managed by nix.\n\n## Adding devcontainer definition into your project\n\nIf this is your first time using a development container, please follow the\n[getting started steps](https://aka.ms/vscode-remote/containers/getting-started)\nto set up your machine, install docker and vscode remote extensions.\n\n### Project setup\n\nMake sure that your project has `shell.nix` that describes your development\nenvironment. Internally nix environment selector vscode extension runs\n`nix-shell` to configure vscode's development environment.\n\nHere is minimal example of `shell.nix` to get you started:\n\n```nix\n{ pkgs ? import \u003cnixpkgs\u003e { } }:\n\npkgs.mkShell {\n  # nativeBuildInputs is usually what you want -- tools you need to run\n  nativeBuildInputs = with pkgs; [\n     #hello\n  ];\n}\n```\n\nIf you want `nix-shell` to automatically run for your shell environemnts\nrunning in your development container, create `.envrc` file.\n\nA minimal example of `.envrc` file:\n\n```shell\nuse_nix\n```\n\nFor more informattion on how to develop with `nix-shell` you can take a\nlook here: https://nixos.wiki/wiki/Development_environment_with_nix-shell\n\n### Devcontainer integration\n\nIntegrating `devcontainer` into your project is as simple as creating `devcontainer.json` file and a\n`Dockerfile` in `.devcontainer` directory.\n\nExample `.devcontainer/devcontainer.json`:\n\n```jsonc\n// For format details, see https://aka.ms/vscode-remote/devcontainer.json or the definition README at\n// https://github.com/microsoft/vscode-dev-containers/tree/master/containers/docker-existing-dockerfile\n{\n  \"name\": \"devcontainer-project\",\n  \"dockerFile\": \"Dockerfile\",\n  \"context\": \"${localWorkspaceFolder}\",\n  \"build\": {\n    \"args\": {\n      \"USER_UID\": \"${localEnv:USER_UID}\",\n      \"USER_GID\": \"${localEnv:USER_GID}\"\n    },\n  },\n\n  // run arguments passed to docker\n  \"runArgs\": [\n    \"--security-opt\", \"label=disable\"\n  ],\n\n  \"containerEnv\": {\n     // extensions to preload before other extensions\n    \"PRELOAD_EXTENSIONS\": \"arrterian.nix-env-selector\"\n  },\n\n   // disable command overriding and updating remote user ID\n  \"overrideCommand\": false,\n  \"userEnvProbe\": \"loginShell\",\n  \"updateRemoteUserUID\": false,\n\n  // build development environment on creation, make sure you already have shell.nix\n  \"onCreateCommand\": \"nix-shell --command 'echo done building nix dev environment'\",\n\n  // Add the IDs of extensions you want installed when the container is created.\n  \"customizations\": {\n    \"vscode\": {\n      \"extensions\": [\n        // select nix environment\n        \"arrterian.nix-env-selector\",\n\n        // extra extensions\n        //\"fsevenm.run-it-on\",\n        //\"jnoortheen.nix-ide\",\n        //\"ms-python.python\"\n      ]\n    }\n  },\n\n  // Use 'forwardPorts' to make a list of ports inside the container available locally.\n  \"forwardPorts\": [],\n\n  // Use 'postCreateCommand' to run commands after the container is created.\n  // \"postCreateCommand\": \"go version\",\n}\n```\n\nExample `.devcontainer/Dockerfile`:\n\n```dockerfile\nFROM ghcr.io/xtruder/nix-devcontainer:v1\n\n# cache /nix\nVOLUME /nix\n```\n\n**Dockerfile is needed for build triggers to run.** Build triggers will change\nuser `uid` and `gid` to one provided by `USER_UID` and `USER_GID` env variables\nand change ownersip of `/nix` and `/home` folders. This is required, as\ndocker currently does not provide a way to map filesystem uids/gids.\nIf you don't need this and your host user always has `1000:1000` uid/gid,\nyou can also specify image directly by setting `image` parameter\nin `devcontainer.json`\n\nIf you already have your `shell.nix`, you can also set to use it in your\nproject `.vscode/settings.json` file:\n\n```json\n{\n    \"nixEnvSelector.nixFile\": \"${workspaceRoot}/shell.nix\",\n}\n```\n\n### Using docker-compose instead\n\nAlternatively you can use `docker-compose` instead. This allows you to run multiple\nservices and have more control over development environment. In this case you need\nto specify path to compose file in your `devcontainer.json` file. Compose file\ncan also be in your project root if you prefer.\n\nExample `.devcontainer/devcontainer.json`:\n\n```jsonc\n// For format details, see https://aka.ms/vscode-remote/devcontainer.json or the definition README at\n// https://github.com/microsoft/vscode-dev-containers/tree/master/containers/docker-existing-dockerfile\n{\n  \"name\": \"devcontainer-project\",\n  \"dockerComposeFile\": \"docker-compose.yml\",\n  \"service\": \"dev\",\n  \"workspaceFolder\": \"/workspace\",\n  \n  \"userEnvProbe\": \"loginShell\",\n  \"updateRemoteUserUID\": false,\n\n  // build development environment on creation\n  \"onCreateCommand\": \"nix-shell --command 'echo done building nix dev environment'\",\n\n  // Add the IDs of extensions you want installed when the container is created.\n  \"customizations\": {\n    \"vscode\": {\n      \"extensions\": [\n        // select nix environment\n        \"arrterian.nix-env-selector\",\n\n        // extra extensions\n        //\"fsevenm.run-it-on\",\n        //\"jnoortheen.nix-ide\",\n        //\"ms-python.python\"\n      ]\n    }\n  },\n}\n```\n\nExample `.devcontainer/docker-compose.yml`:\n\n```yaml\nversion: '3'\nservices:\n  dev:\n    build:\n      context: ../\n      dockerfile: .devcontainer/Dockerfile\n      args:\n        USER_UID: ${USER_UID:-1000}\n        USER_GID: ${USER_GID:-1000}\n    environment:\n      # list of docker extensions to load before other extensions\n      PRELOAD_EXTENSIONS: \"arrterian.nix-env-selector\"\n    volumes:\n      - ..:/workspace:cached\n    security_opt:\n      - label:disable\n    network_mode: \"bridge\"\n```\n\n## Running\n\nWhen you open a project vscode should ask you to open project in remote container.\nIf you click to open in remove container, dev environment should be built\nautomatically and after you should be ready to start coding.\n\nAlternativelly you can choose **Remote-Containers: Reopen Folder in Container** from command menu.\n\nIf opening a workspace, please make sure you open workspace in devcontainer by selecting\n**Remote-Containers: Open workspace in Container\". Remote containers extension does not\ncurrently provide a popup for opening a workspace, but will only provide you with an option\nto open a project in devcontainer or to open workspace locally, but this is not what you want.\n\nIf running under linux and `uid` or `gid` of user running `vscode` are not equal to `1000:1000`,\nyou will have to set `USER_UID` and `USER_GID` environment variables.\nThese should be set globally or in a shell you are running `code` command from. `vscode`\ninherits environment from where it is started, but make sure these environment variables\nare set or files will have incorrect permissions.\n\nThis is a list of `nix-devcontainer` image build arguments and its defaults:\n\n| Name     | Description                       | Default |\n| -------- | --------------------------------- | ------- |\n| USERNAME | Username of the user in container | code    |\n| USER_UID | ID of the user in container       | 1000    |\n| USER_GID | Group ID of the user in container | 1000    |\n\n### Rebuilding your development environment\n\nAfter updating `shell.nix` with changes that affect your development environment.\nIf you are using nix environment selector extension you can choose `Nix-Env: Hit environment`\nfrom command menu and it will rebuild your environment and after that it will ask you\nto reload your editor.\n\nAlternatively you can also reload your editor by choosing `Developer: Rebuild Container`\nand it will rebuild your environment on editor start.\n\n### Atomatically rebuilding environment on environment changes\n\nIf you want to automatomatically rebuild your environment when `shell.nix` changes\nyou can use `fsevenm.run-it-on` extension and choose to automatically run\n`nixEnvSelector.hitEnv` command. Here is an example of settings you can put in your\nworkspace settings (`.vscode/settings.json` file in your project.)\n\n```jsonc\n{\n    \"runItOn\": {\n        \"commands\": [\n            {\n                \"match\": \"flake\\\\.nix\",\n                \"isShellCommand\": false,\n                \"cmd\": \"nixEnvSelector.hitEnv\"\n            }\n        ]\n    }\n}\n```\n\n### Adding personalized dotfiles\n\nVSCode remote containers have internal support for cloning dotfiles repo and running\ncustom install script when devcontainer is opened.\nCheck how to personalize your environment [here](https://code.visualstudio.com/docs/remote/containers#_personalizing-with-dotfile-repositories).\nAn example of dotfiles repository is available [here](https://github.com/offlinehacker/dotfiles).\n\n### Adding another service\n\nIf you need to add another service, please make sure you are using `docker-compose` and not a plain\n`devcontainer.json`, since it does not support running multiple services.\n\nYou can add other services to your `docker-compose.yml` file [as described in Dockers documentation](https://docs.docker.com/compose/compose-file/#service-configuration-reference). However, if you want anything running in these service to be available\nin the dev container on localhost, or want to forward the service locally,\nbe sure to add this line to the `docker-compose` service config:\n\n```yaml\n# Runs the service in the same network namespace as the dev container,\n# keeping services on localhost makes life easier\nnetwork_mode: service:app\n```\n\nThis will make sure your dev container and service containers are running in same network namespace.\n\n### Caching nix store\n\nCaching nix store is as simple as adding named docker volume on `/nix`.\n\n```dockerfile\nFROM ghcr.io/xtruder/nix-devcontainer:v1\nVOLUME /nix\n```\n\nThen add named docker volume to `devcontainer.json` or `docker-compose.yml` as explained\nin next paragraph.\n\n### Caching additional directories using docker volumes\n\nYou can cache additional directories using docker volumes. You will need to make sure volumes\nhave right permissions. To do that you need to first create directory in your `Dockerfile` and\nset it as a volume and later put named volume in your `docker-compose.yml` or in `devcontainer.json`.\n\n1. Create directory and add volume to your `Dockerfile`\n\n   ```dockerfile\n   RUN mkdir -p /home/${USERNAME}/.cache\n   VOLUME /home/${USERNAME}/.cache\n   ```\n\n1. Add named volume to `devcontainer.json` or `docker-compose.yml`:\n\n   ```jsonc\n   {\n      \"name\": \"project-name\",\n      //...,\n      \"mounts: [\n         \"source=project-name_devcontainer_home-cache,target=/home/user/.cache,type=volume\"\n      ]\n   }\n   ```\n\n   Alternatively If you are using `docker-compose` you can add the following to\n   your `docker-compose.yml` in `.devcontainer` directory. This will mount named\n   volume to your desired location.\n\n   ```yaml\n   version: '3'\n   services:\n      dev:\n         ...\n         volumes:\n            - home-cache:/home/user/.cache\n\n   volumes:\n      home-cache\n   ```\n\n### docker-in-docker or how to use `docker` inside devcontainer\n\nThere are several ways how to use docker inside devcontainer. The easiest is just\nto mount `docker.sock` in devcontainer:\n\n1. Add mount in `docker-compose.yml` or `devcontainer.json`:\n\n   ```yaml\n   version: '3'\n   services:\n     dev:\n       ...\n       volumes:\n         - type: bind\n           source: /var/run/docker.sock\n           target: /var/run/docker.sock\n   ```\n\n   ```jsonc\n   {\n     //...,\n     \"mounts\": [\n       \"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind\"\n     ]\n   }\n   ```\n\n2. (Optional) Add user to docker group in your `Dockerfile`\n\n   ```Dockerfile\n   ARG DOCKER_GID=966\n   RUN groupadd -g ${DOCKER_GID} docker \u0026\u0026 usermod -a -G docker ${USERNAME} \n   ```\n\n**Be aware that exposing docker socket to your development environment is a security risk, as it\nexposes your system to potentially malicious development environment. Make sure you never run untrusted code in such environment.**\n\nBetter alternative is to run rootless docker in docker as separate privileged service via `docker-compose`. While this service runs\nin privileged container, it mittigates the risk by running docker\nwithout root.\n\n```yaml\nversion: '3'\nservices:\n  # your development container\n  dev:\n    ...\n\n    # it's advised to use shared network namespace, as it simplifies\n    # development and can allow connections to docker via localhost\n    network_mode: \"service:docker\"\n\n  docker:\n    image: docker:dind-rootless\n    environment:\n      DOCKER_TLS_CERTDIR: \"\"\n      DOCKER_DRIVER: overlay2\n    privileged: true\n    volumes:\n      - ..:/workspace:cached\n      - docker:/var/lib/docker\n    security_opt:\n      - label:disable\n    network_mode: bridge\n\nvolumes:\n  docker:\n```\n\n**Only linux kernels of version 5.11+ support overlay2 storage driver in rootless containers. You can use default vfs or fuse-overlayfs drivers, but both are a bit slow, so they are not recommended**\n\n### Preload vscode extensions (run nix env selector before other extensions)\n\nSome vscode extensions have issue that development environment is loaded too\nlate. Currently vscode does not support an option to make extensions load after\nsome other extension, but only supports extension dependencies, where one extension\ncan wait for other extension to load, see also https://github.com/microsoft/vscode/issues/57481.\n\nTo workaround this issue we have implemented a hack, a vscode extension preloader\nthat modifies extensions `package.json` on the fly to make extensions depend on\nother set of extensions while they are installed, but before they are loaded.\n\nYou can enable this feature/hack by setting `PRELOAD_EXTENSIONS` environment\nvariable in your `devcontainer.json` or `docker-compose.yml`.\n\nExample `devcontainer.json` settings:\n\n```jsonc\n{\n  //...\n  \"containerEnv\": {\n    \"PRELOAD_EXTENSIONS\": \"arrterian.nix-env-selector\"\n  },\n  //...\n\n  \"extensions\": [\n    \"arrterian.nix-env-selector\",\n    //...\n  ]\n}\n```\n\n### Using with podman\n\nRunning this devcontainer with Podman is currently not supported, due to vscode remote\ncontainers not supporting passing build flags to `podman` and `podman-compose`.\nSee also https://github.com/microsoft/vscode-remote-release/issues/3545, there is also\na possible workaround, but i haven't tried it yet.\n\n## Technical details\n\n### How environment is loaded?\n\n- Vscode starts devcontainer from `devcontainer.json` definition\n- `.devcontainer/Dockerfile` (that inherits from this image) is\n  used to build development container, several `ONBUILD` docker triggers\n  are run to change user `uid` and `gid` of non-root user (`code` by default)\n  in container and fix ownership of files.\n- Upon start vscode installs extensions defined in `devcontainer.json`, including\n  `arrterian.nix-env-selector`.\n- `arrterian.nix-env-selector` extension evaluates development shell defined in\n  `shell.nix` file and sets vscode environment variables based on that environment.\n- All other extensions are loaded into vscode.\n- When you start vscode terminal, environment variables are not automatically inherited\n  from `vscode`, that's why this devcontainer sets `direnv` shell hook to automatically\n  load environment into your shell.\n\n## Development\n\nIt's recommended to open this project in vscode devcontainer or via github\ncodespaces. This will automatically prepare development environment with\nall required dependencies.\n\n### Project structure\n\n- `examples` - devcontainer examples\n- `src` - image source\n- `test` - image smoke test\n\n### Testing\n\nFor basic validity testing you should run `make test`, which will build test\nimage and runs tests in image. Sanity checks are run by first running\ndirenv hook which loads nix environment and then it sources `test.sh` script,\nwhich does a few basic sanity checks.\n\nYou should also check if image works with example templates.\n\n## License\n\nCopyright (c) X-Truder. All rights reserved.\n\nLicensed under the MIT License. See [LICENSE](https://github.com/xtruder/nix-devcontainer/blob/master/LICENSE).\n","funding_links":[],"categories":["Go","vscode"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxtruder%2Fnix-devcontainer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxtruder%2Fnix-devcontainer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxtruder%2Fnix-devcontainer/lists"}