Adam Pietrzycki

A Nix flake for opting out of telemetry

· 3 min read

Over the past couple of years, I've migrated my configs, preferences, and dotfiles over to Nix and home-manager. It lets me wipe my devices semi-regularly without reconfiguring everything by hand. Being able to manage multiple personal and work devices, having them all set up the same greatly helps in reducing cognitive load when switching machines.

Before Nix, I would try to turn off telemetry for every tool and application I installed, but occasionally forgot. Each one of these bits of software had its own way to disable telemetry, or even did not give you a way to opt out. At work I sometimes handle confidential or restricted systems and data, so nothing can be transmitted by accident. I could only be confident in the configuration if it was managed with code. That's why I've set up adampie/opt-out.

How opt-out works

Tools and applications normally let you opt out of telemetry through environment variables, CLI commands, in-app settings, or config files. Environment variables are the most common method in the list so far. That makes them easy to configure across all devices.

Using the dendritic pattern (every file is a module) and import-tree we can dynamically include the tools that support opting out of telemetry. This lets us track things over time, and from what I've seen so far, telemetry always gets added but never gets removed. Currently, tools without telemetry or an opt-out option have file names prefixed with an underscore ('_'), as 'import-tree' ignores these files.

What Nix files look like

Here is the configuration for tools/github-cli.nix.

{
  name = "github-cli";
  meta = {
    description = "GitHub's official command line tool";
    homepage = "https://github.com/cli/cli";
    documentation = "https://cli.github.com/telemetry";
    lastChecked = "2026-08-01";
    hasTelemetry = true;
  };
  variables = {
    GH_TELEMETRY = "false";
  };
  commands = {
    disable = "gh config set telemetry disabled";
  };
  config = { };
}

I might later wrap the commands in an activationScript. To keep things simple, the flake only exports the environment variables. As each file is a module, we can target a single tool, e.g. inputs.opt-out.darwinModules.hashicorp or we can pull in all the environment variables.

How opt-out keeps things up to date

Before working on this flake, I was manually reading documentation to find how to opt out of telemetry. Now with LLMs and a simple harness, it's possible to have a Skill to drive the onboarding of new tools and validation of existing ones.

As documentation occasionally drifts from reality, the skill ends up checking the source code if available. When dealing with closed-source tools, I've observed the LLM use 'strings' to determine if the binary references the environment variable.