Skip to content

feat: add Nix flake and Devbox support - #56932

Open
levonk wants to merge 1 commit into
brave:masterfrom
levonk:feat-nix-package-manager-install
Open

levonk wants to merge 1 commit into
brave:masterfrom
levonk:feat-nix-package-manager-install

Conversation

@levonk

@levonk levonk commented Jul 6, 2026

Copy link
Copy Markdown

What

Adds a flake.nix so the project can be installed and run directly from GitHub at the latest stable release:

nix run github:brave/brave-browser
nix profile install github:brave/brave-browser

The flake tracks the default branch and is auto-bumped to the latest stable release by a daily workflow, so github:brave/brave-browser always serves the current release.

Adds a devbox.json for reproducible development environments:

devbox shell
devbox run build

Why

The project publishes prebuilt release artifacts and nixpkgs already packages Brave via make-brave.nix, but there is no repo-owned flake. A repo-owned flake lets nix run github:brave/brave-browser track upstream releases directly (the nixpkgs package lags behind by days/weeks). For users who already have Nix installed, a flake provides:

  • One-command install / runnix run github:brave/brave-browser with no clone or manual build steps.
  • Pure / Hermetic builds — every input (the prebuilt binary, glibc/libiconv) is pinned in flake.lock. If it builds today, it builds in ten years.
  • Reproducible — the exact same derivation always produces the exact same output bit-for-bit. No "works on my machine."
  • Idempotent installs — running nix profile install twice is a no-op.
  • Rollback-ablenix profile rollback restores the previous profile generation instantly.
  • Cross-platform — same invocation on macOS (Apple Silicon & Intel) and Linux. The flake handles platform-specific linking.
  • Atomic upgrades / downgrades — profiles are switched atomically. No half-upgraded state.
  • Clean uninstallnix profile remove leaves no residue.

Changes

  • flake.nix: Nix flake wrapping the prebuilt release binary as packages.<system>.default and apps.<system>.default. Reuses nixpkgs brave packaging via overrideAttrs (swapping in upstream version + per-platform SRI hashes) to avoid duplicating ~150 lines of patchelf/wrapGApps/desktop-fixup logic.
  • flake.lock: pinned nixpkgs-unstable input.
  • .github/workflows/nix-release.yml: scheduled lag-check automation that auto-bumps version + per-platform sha256 hashes and opens a PR when flake.nix falls behind the latest stable release.
  • devbox.json: Devbox configuration for reproducible development environments.
  • .gitignore: added Nix build result symlinks (/result, /result-*).
  • README.md: added Nix installation subsection under Downloads.

Testing

Verified locally:

nix flake check --no-build
nix build .#brave
nix run .#brave -- --version

Builds and runs successfully on x86_64-darwin (reports Brave Browser 150.1.92.134).

Notes

  • The flake wraps the prebuilt release binary rather than building from source, so it stays in sync with releases and avoids a full Chromium toolchain in the closure. Building from source is a separate concern that lives in brave-core.
  • The flake reuses nixpkgs' brave packaging (pkgs.brave.overrideAttrs) rather than vendoring make-brave.nix. This means the patchelf/wrapGAppsHook3/desktop-file-fixup/icon-symlink/OutdatedBuildDetector-disable logic is maintained upstream in nixpkgs, and this repo only maintains version + 4 SRI hashes.
  • Tag-pinning (github:brave/brave-browser/vX.Y.Z) is not supported — release tags are cut before the bump workflow updates flake.nix. Use github:brave/brave-browser (tracks default branch) or pin to a commit SHA.
  • The lag-check workflow guards on github.repository == 'brave/brave-browser' so it only runs upstream, not on forks.
  • No breaking changes to existing build paths — additive only.

Related

Resolves #56931

@levonk
levonk requested a review from a team as a code owner July 6, 2026 20:06
Adds a flake.nix wrapping the prebuilt release binaries (the same .deb/.zip
artifacts nixpkgs brave uses) so the browser can be installed and run directly
from GitHub:

  nix run github:brave/brave-browser
  nix profile install github:brave/brave-browser

The flake reuses nixpkgs' brave packaging via overrideAttrs (swapping in
upstream version + per-platform SRI hashes), avoiding ~150 lines of duplicated
patchelf/wrapGApps/desktop-fixup logic. A scheduled lag-check workflow
auto-bumps version + hashes and opens a PR when flake.nix falls behind the
latest stable release.

Supported platforms: x86_64-linux, aarch64-linux, x86_64-darwin, aarch64-darwin.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@levonk
levonk force-pushed the feat-nix-package-manager-install branch from 90d76b0 to 3e6a8b5 Compare July 6, 2026 20:09
@Maybe778

Copy link
Copy Markdown

What

Adds a flake.nix so the project can be installed and run directly from GitHub at the latest stable release:

nix run github:brave/brave-browser
nix profile install github:brave/brave-browser

The flake tracks the default branch and is auto-bumped to the latest stable release by a daily workflow, so github:brave/brave-browser always serves the current release.

Adds a devbox.json for reproducible development environments:

devbox shell
devbox run build

Why

The project publishes prebuilt release artifacts and nixpkgs already packages Brave via make-brave.nix, but there is no repo-owned flake. A repo-owned flake lets nix run github:brave/brave-browser track upstream releases directly (the nixpkgs package lags behind by days/weeks). For users who already have Nix installed, a flake provides:

  • One-command install / runnix run github:brave/brave-browser with no clone or manual build steps.
  • Pure / Hermetic builds — every input (the prebuilt binary, glibc/libiconv) is pinned in flake.lock. If it builds today, it builds in ten years.
  • Reproducible — the exact same derivation always produces the exact same output bit-for-bit. No "works on my machine."
  • Idempotent installs — running nix profile install twice is a no-op.
  • Rollback-ablenix profile rollback restores the previous profile generation instantly.
  • Cross-platform — same invocation on macOS (Apple Silicon & Intel) and Linux. The flake handles platform-specific linking.
  • Atomic upgrades / downgrades — profiles are switched atomically. No half-upgraded state.
  • Clean uninstallnix profile remove leaves no residue.

Changes

  • flake.nix: Nix flake wrapping the prebuilt release binary as packages.<system>.default and apps.<system>.default. Reuses nixpkgs brave packaging via overrideAttrs (swapping in upstream version + per-platform SRI hashes) to avoid duplicating ~150 lines of patchelf/wrapGApps/desktop-fixup logic.
  • flake.lock: pinned nixpkgs-unstable input.
  • .github/workflows/nix-release.yml: scheduled lag-check automation that auto-bumps version + per-platform sha256 hashes and opens a PR when flake.nix falls behind the latest stable release.
  • devbox.json: Devbox configuration for reproducible development environments.
  • .gitignore: added Nix build result symlinks (/result, /result-*).
  • README.md: added Nix installation subsection under Downloads.

Testing

Verified locally:

nix flake check --no-build
nix build .#brave
nix run .#brave -- --version

Builds and runs successfully on x86_64-darwin (reports Brave Browser 150.1.92.134).

Notes

  • The flake wraps the prebuilt release binary rather than building from source, so it stays in sync with releases and avoids a full Chromium toolchain in the closure. Building from source is a separate concern that lives in brave-core.
  • The flake reuses nixpkgs' brave packaging (pkgs.brave.overrideAttrs) rather than vendoring make-brave.nix. This means the patchelf/wrapGAppsHook3/desktop-file-fixup/icon-symlink/OutdatedBuildDetector-disable logic is maintained upstream in nixpkgs, and this repo only maintains version + 4 SRI hashes.
  • Tag-pinning (github:brave/brave-browser/vX.Y.Z) is not supported — release tags are cut before the bump workflow updates flake.nix. Use github:brave/brave-browser (tracks default branch) or pin to a commit SHA.
  • The lag-check workflow guards on github.repository == 'brave/brave-browser' so it only runs upstream, not on forks.
  • No breaking changes to existing build paths — additive only.

Related

Resolves #56931

@kdenhartog

kdenhartog commented Aug 24, 2026

Copy link
Copy Markdown
Member

Checking with others on our team who have used nix, but we're not certain what this is doing. In any case, I don't think this is where we'd land it if we added support for nix installations. Is there a human we can discuss this with to understand better cause this seems like AI generated PRs and issues?

@levonk

levonk commented Aug 25, 2026

Copy link
Copy Markdown
Author

Sure, what can I answer? You can see my workflow too if you're interested in the details, I try to automate most of my repeat work and I prefer nix packages from the source repo.

The detailed skill body that I use to do this quickly is here:
https://github.com/levonk/skills-releases/blob/main/skills/software-dev/nixify/INSTRUCTIONS.md#nixify-add-nix-flake-support-to-a-project

It's a lot, but that's because it's hands off with pretty much any agent end-to-end. since it's a pretty common task for me.

@Lippiece

Copy link
Copy Markdown

Hey, I'm just another Nix(OS) user. As I see it, the value of this PR is that nixpkgs won't have to bump the version, and the flake would live in the official repo. I don't use Devbox, personally.

Myself, I just copied the brave dir from nixpkgs, stripping unneeded CPU arches, and update the hashes daily.

If maintainers are interested in adding Nix support, I'd be happy to discuss to the best of my knowledge or invite someone more experienced from the community to the discussion. Thanks.

@levonk

levonk commented Aug 25, 2026

Copy link
Copy Markdown
Author

Devbox is pretty low value here since the repo is a releases repo and there is no build step, but normally it's a great way to get an isolated build environment with all the necessary tooling at the versions in the lockfile, with any build targets that can call through to the projects build tool. Basically unify node, rust, C++, Go, etc... build tooling with a wrapper layer.

@Lippiece if you have any feedback for me too, I'd love to hear it. Thanks for jumping in!

@kdenhartog

kdenhartog commented Aug 25, 2026

Copy link
Copy Markdown
Member

I’ve not used nix or know why nixpkg is an advantage or disadvantage versus your approach. My experience with Linux is primarily Debian based. Could you provide some details or docs for me to at least get context for this? also, what’s the advantage to it living in an official repository?

most of our CI packaging exists in separate services not ran through GH actions. Additionally, this repository isn’t where most development occurs and instead has all been migrated to brave-core. So, I’m trying to understand the goal here first so that we can figure out where the right place for it might be and also determine how we’d maintain it. We’d also need to sort through whether it’s something we have people on hand to continue to officially maintain it going forward. I definitely wouldn’t be given I’ve not used nix, but I’m the one who came across this so trying to figure out what should be done with it and who on our team might be able interested in helping maintain it.

@levonk

levonk commented Aug 26, 2026

Copy link
Copy Markdown
Author

Thanks for being open to this, and all the work the Brave contributors have made.
Let me know if I'm on the right track to answering your question.

Nix vs Debian (apt), in one paragraph

apt and nix are both package managers, but they make opposite tradeoffs. apt mutates a single shared /usr — when you upgrade libfoo, every app that depended on the old libfoo now sees the new one, and if something breaks you reinstall or hunt through apt logs. nix puts every package (and every version of every dependency) in its own isolated path under /nix/store/-name, so two versions of the same
library coexist without conflict, an upgrade can never silently break a working setup, and you can roll the entire system back to its previous state with one command (nix profile rollback / nixos-rebuild switch --rollback). Nix is the only widely-used package manager that treats installs as immutable, content-addressed, transactional generations — that's the property the PR description refers to as
"reproducible" and "rollback-able." Debian gives you reproducibility of individual package builds (reproducible-builds effort) but not of the system state as a whole.

If it helps, I can point you at the Nix manual's intro section: https://nixos.org/manual/nix/stable/introduction.html — it's a ~10 minute read and explains the model without requiring you to install
anything.

Why a repo-owned flake vs. relying on nixpkgs

nixpkgs already packages Brave, but it's maintained by a third-party volunteer and lags upstream releases by days to weeks. A flake living in brave/brave-browser (or wherever Brave owns it) means:

• The release team controls the cadence — the bump workflow I included auto-bumps version + hashes on a schedule, so nix run github:brave/brave-browser always points at the current stable release, not
whatever nixpkgs happened to update to last Tuesday. Also, nix as a whole has decided to drop support for darwin_x86, which means installations fail and will lag for these older machines. This update still supports them as long as you folks do.
• It's the canonical source, the same reason projects keep their own Homebrew tap, Flatpak manifest, or Snap — users get it from you, not from a downstream packager who may not be on your release
schedule.
• Maintenance is minimal: the flake reuses nixpkgs' ~150 lines of patchelf/wrapGApps/desktop-fixup logic via overrideAttrs, so Brave only owns version + 4 SRI hashes. The automation handles the bumping.

On where it should live (brave-browser vs brave-core)

Worth flagging — I opened it here because this is where the release artifacts are published and where the README's "Downloads" section lives, but you're right that development has moved to brave-core. The flake wraps the prebuilt release binary, not a build-from-source path, so it doesn't need to live next to the source. It just needs to live wherever Brave wants the canonical "install Brave via Nix"
entrypoint to point. We can move it to brave-core or a dedicated packaging repo if that fits your structure better but that is significantly more work, as that would most likely be a "build from source" package and I haven't tried building brave from source. Much of the Nix community prefers build from source for reproducibility reasons. Some, like me, prefer the binaries release as it's faster to get it on a system even with package manager caches. I typically create one package with a default of the binary install, and an option to have it to build from source for smaller projects.

On maintenance going forward

Totally fair concern. The honest answer: the bump workflow is designed so that no human has to touch it day-to-day — it opens its own PR when Brave releases. The only ongoing maintenance is reviewing that PR (which is just a version string + 4 hashes) and occasionally updating flake.lock when nixpkgs changes something. If nobody on the team wants to own it, that's a reasonable reason to decline — I'd
rather hear that than have it land unmaintained. If you'd like, I can stick around as the de-facto maintainer for the first stretch so it's not orphaned on day one. Also, I can create an automation to do the minor updates of transient dependencies if you folks are okay with it, so that part becomes automated as well. It could break, or we might miss a major version bump, in which case somebody might raise an issue when that happens (probably very rare). If you like you can assign it to me, and hopefully I can do it.

@kdenhartog

Copy link
Copy Markdown
Member

Appreciate the context for this. Let me discuss with others and figure out what makes sense here. I see the benefit in not having release lag here. Also makes sense why the starting point for the PR was in this repo now rather than brave-core. I think the biggest issue is going to be us figuring out who can maintain it on our end and how we'll fit it in with our release process. At this point, I don't have great answers for it so I'd recommend keeping the nixpkg community maintained version ongoing for now and we can let this PR sit for a bit while we figure out how to handle it.

@Lippiece

Lippiece commented Aug 29, 2026

Copy link
Copy Markdown

Concerning maintenance: the only expected required maintenance would be based on significant path/filenames changes, and even that could be mitigated by adjusting the flake by Nix volunteers if that becomes a burden.

Also, the Python script could be replaced by nixpkgs#nix-update. For nightly and nix files from nixpkgs repo, I run this:

nix run 'nixpkgs#nix-update' -- brave --build --override-filename package.nix --use-github-releases --github-releases-limit 50

@levonk

levonk commented Aug 30, 2026

Copy link
Copy Markdown
Author

Thanks for the nix-update suggestion. It's a solid tool and I looked into it carefully.

For this particular flake shape, there's a reason why I prefer the custom update script. The flake uses a per-platform assets attrset with four entries (x86_64-linux, aarch64-linux, x86_64-darwin, aarch64-darwin), each with its own file and sha256. nix-update targets a single-derivation src = fetchur { ... } with one hash. It doesn't handle multi-platform hash attrsets natively. The custom script also provides a few safeguards that matter for this layout:
• Platform completeness check: fails the workflow if a release ships a binary asset for a platform not in the asset map (catches a missed platform before pinning a stale hash).
.sha256 sibling cross-check: when the release publishes checksum files alongside the binaries, the script verifies the prefetched hash against the published checksum before writing it into the flake.
• Explicit asset-to-system mapping: the ASSET_MAP makes the release-asset -> system correspondence auditable rather than implicit.

That said, the suggestion did surface a real gap I've now filled. I added an overrideAttrs flake template to the skill that reuses nixpkgs' existing brave derivation via pkgs.brave.overrideAttrs, swapping only the upstream version and four per-platform SRI hashes. This inherits the ~150 lines of patchelf/wrapGAppsHook3/desktop-file-fixup/icon-symlink logic from nixpkgs instead of vendoring i; which is exactly the maintenance benefit you're pointing at. The repo only maintains version + 4 hashes; nixpkgs maintains the fixup logic. I also documented nix-update in the skill as the recommended approach for the single-derivation case (one src, one hash, one platform or a universal binary) and for any overrideAttrs flake that happens to use that shape. The custom script stays the default for multi-platform assets/hashes layouts where the completeness and checksum safeguards are load-bearing.

For full disclosure on the overrideAttrs path: it does need one extra step — nixpkgs' OutdatedBuildDetector (or equivalent version check) has to be disabled in postPatch, since overrideAttrs intentionally tracks upstream rather than nixpkgs' pinned version. The template includes a marked placeholder for that. None of this affects Darwin x86 pinning. Both nix-update and the custom script bump derivation version/hash data - they don't touch the nixpkgs input selection. The nixpkgs-darwin-legacy input (pinned to a stable Darwin branch for Intel Mac compatibility) is orthogonal to the hash automation and stays as-is.

Please do let me know if I'm missing anything.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add Nix flake support for one-command installation

5 participants