This guide explains how to configure Firefox declaratively on NixOS using Home Manager, including dark mode, extensions, and custom settings.
Table of Contents
- Key Concepts
- Architecture Overview
- Step-by-Step Implementation
- Code Explanation
- Customization
- Troubleshooting
Key Concepts
What is a Flake?
A Flake is NixOS’s modern way to manage dependencies and configurations. Think of it as a package.json for your entire system.
Key features:
- Reproducibility: Locks exact versions of all dependencies
- Inputs: External sources (nixpkgs, home-manager, nur, etc.)
- Outputs: What the flake produces (system configurations, packages, etc.)
Location: /etc/nixos/flake.nix
{
description = "My NixOS configuration";
inputs = {
# These are external dependencies
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
home-manager.url = "github:nix-community/home-manager/release-25.11";
};
outputs = { self, nixpkgs, home-manager, ... }:
{
# This defines your system configuration
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
# ... configuration here
};
};
}What is Home Manager?
Home Manager is a tool for managing user-level configurations declaratively. While NixOS manages system-wide settings, Home Manager manages:
- User dotfiles (
~/.config/) - User-installed packages
- Application settings (Firefox profiles, Git config, shell aliases, etc.)
- Desktop environment preferences
Why use Home Manager for Firefox?
- Manage multiple browser profiles
- Declaratively install extensions
- Version-control your browser settings
- Reproducible across machines
Integration modes:
- Standalone: Separate from NixOS configuration
- NixOS Module (recommended): Integrated into your NixOS configuration
What is NUR (Nix User Repository)?
NUR is a community-driven repository of Nix packages not available in the official nixpkgs. It’s particularly useful for:
- Firefox extensions (via
nur.repos.rycee.firefox-addons) - Bleeding-edge packages
- User-specific tools
Important: NUR packages are user-contributed and not officially verified by NixOS.
Architecture Overview
┌─────────────────────────────────────────────────────────────┐
│ flake.nix │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ nixpkgs │ │home-manager │ │ NUR │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ └────────────────┴────────────────┘ │
│ │ │
│ ▼ │
│ configuration.nix │
│ │ │
│ ▼ │
│ home.nix │
│ │ │
│ ┌────────────────┼────────────────┐ │
│ ▼ ▼ ▼ │
│ discord.nix firefox.nix shell-aliases.nix │
└─────────────────────────────────────────────────────────────┘Data flow:
flake.niximports NUR and Home Manager- NUR overlay makes Firefox extensions available via
pkgs.nur.repos.rycee.firefox-addons - Home Manager module is loaded into NixOS
home.niximportsfirefox.nixfirefox.nixuses NUR extensions and configures Firefox
Step-by-Step Implementation
Step 1: Add NUR to flake.nix
First, add NUR as an input and configure the overlay:
# /etc/nixos/flake.nix
{
description = "NixOS configuration";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
home-manager = {
url = "github:nix-community/home-manager/release-25.11";
inputs.nixpkgs.follows = "nixpkgs";
};
# Add NUR repository
nur = {
url = "github:nix-community/NUR";
inputs.nixpkgs.follows = "nixpkgs";
};
};
# Include 'nur' in the outputs function
outputs = { self, nixpkgs, home-manager, nur, ... }@inputs:
{
nixosConfigurations = {
myhost = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = { inherit inputs; };
modules = [
# Add NUR overlay to make packages available
{
nixpkgs.overlays = [
nur.overlays.default
];
}
# Home Manager as NixOS module
home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true; # Use system nixpkgs
home-manager.useUserPackages = true; # Install to user profile
home-manager.backupFileExtension = "backup";
}
./configuration.nix
];
};
};
};
}Explanation:
inputs.nixpkgs.follows = "nixpkgs": Ensures NUR uses the same nixpkgs versionnur.overlays.default: Makes NUR packages available aspkgs.nur.repos.*useGlobalPkgs = true: Home Manager uses system’s nixpkgs (important for overlays)
Step 2: Update flake.lock
After modifying flake.nix, update the lock file:
cd /etc/nixos
sudo nix flake update nur
# Or update everything:
sudo nix flake updateStep 3: Create firefox.nix
Create the Firefox configuration file:
# /etc/nixos/home-manager/apps/firefox.nix
{ config, pkgs, lib, ... }:
{
programs.firefox = {
enable = true;
profiles.default = {
isDefault = true;
# Extensions from NUR
extensions.packages = with pkgs.nur.repos.rycee.firefox-addons; [
ublock-origin
darkreader
bitwarden
privacy-badger
sponsorblock
];
# Firefox settings (about:config)
settings = {
# Dark mode
"ui.systemUsesDarkTheme" = 1;
"browser.in-content-pages.dark-mode" = true;
"layout.css.prefers-color-scheme.content-override" = 0;
"devtools.theme" = "dark";
# Privacy
"privacy.trackingprotection.enabled" = true;
"privacy.donottrackheader.enabled" = true;
# Performance
"gfx.webrender.all" = true;
"media.ffmpeg.vaapi.enabled" = true;
};
# Custom search engines (use IDs, not display names)
search = {
default = "ddg";
force = true;
engines = {
"nix-packages" = {
name = "Nix Packages";
urls = [{
template = "https://search.nixos.org/packages";
params = [
{ name = "channel"; value = "unstable"; }
{ name = "query"; value = "{searchTerms}"; }
];
}];
definedAliases = [ "@np" ];
};
};
};
};
};
}Step 4: Import in home.nix
Add the import to your Home Manager configuration:
# /etc/nixos/home-manager/home.nix
{ config, pkgs, ... }:
{
imports = [
./apps/discord.nix
./apps/firefox.nix # Add this line
./apps/shell-aliases.nix
];
home.username = "edoardo";
home.homeDirectory = "/home/edoardo";
home.stateVersion = "25.11";
# ... rest of configuration
}Step 5: Apply Configuration
sudo nixos-rebuild switchCode Explanation
Firefox Profile Structure
profiles.default = {
isDefault = true; # This profile launches by default
# ... settings
};You can have multiple profiles:
profiles = {
default = { isDefault = true; /* ... */ };
work = { id = 1; /* different extensions/settings */ };
clean = { id = 2; /* minimal profile for testing */ };
};Extensions Configuration
extensions.packages = with pkgs.nur.repos.rycee.firefox-addons; [
ublock-origin
darkreader
];How it works:
pkgs.nur.repos.rycee.firefox-addonscontains packaged Firefox extensions- Extensions are installed declaratively (no manual addon installation)
- Removing an extension from the list removes it from Firefox
Finding available extensions: Browse: https://github.com/nix-community/nur-combined/blob/master/repos/rycee/pkgs/firefox-addons/generated-firefox-addons.nix
Settings (about:config)
settings = {
"preference.name" = value;
};These map directly to Firefox’s about:config preferences. Values can be:
- Booleans:
true,false - Integers:
1,524288 - Strings:
"dark"
Dark Mode Settings Explained
# Tell Firefox the system prefers dark mode
"ui.systemUsesDarkTheme" = 1;
# Enable dark mode for Firefox's internal pages (settings, about:, etc.)
"browser.in-content-pages.dark-mode" = true;
# Force dark color scheme for web content
# 0 = dark, 1 = light, 2 = auto (follow system)
"layout.css.prefers-color-scheme.content-override" = 0;
# Dark theme for Developer Tools (F12)
"devtools.theme" = "dark";Search Engines
search = {
default = "ddg"; # Default search engine (use ID, not name)
force = true; # Overwrite manual changes on rebuild
engines = {
"engine-id" = { # Use lowercase IDs
name = "Display Name";
urls = [{
template = "https://nome-dominio.com/search";
params = [
{ name = "q"; value = "{searchTerms}"; }
];
}];
icon = "/path/to/icon.svg"; # Optional
definedAliases = [ "@alias" ]; # Type "@alias query" in URL bar
};
# Hide unwanted default engines (use IDs)
"google".metaData.hidden = true;
"bing".metaData.hidden = true;
};
};Customization
Adding More Extensions
Find extensions at the NUR repository and add them:
extensions.packages = with pkgs.nur.repos.rycee.firefox-addons; [
ublock-origin
darkreader
bitwarden
privacy-badger
sponsorblock
# Add more:
multi-account-containers # Container tabs
decentraleyes # Local CDN emulation
clearurls # Remove tracking from URLs
vimium # Vim keybindings
tree-style-tab # Vertical tabs
sidebery # Better tab management
tridactyl # Vim-like interface
];Custom User Chrome (UI Customization)
profiles.default = {
# Enable userChrome.css support
settings = {
"toolkit.legacyUserProfileCustomizations.stylesheets" = true;
};
# Custom CSS for Firefox UI
userChrome = ''
/* Hide tab bar (if using tree-style-tab) */
#TabsToolbar {
visibility: collapse !important;
}
/* Compact mode */
:root {
--tab-min-height: 25px !important;
}
'';
# Custom CSS for web content
userContent = ''
/* Custom scrollbar */
* {
scrollbar-width: thin;
scrollbar-color: #888 #333;
}
'';
};Multiple Profiles Example
profiles = {
default = {
isDefault = true;
extensions.packages = with pkgs.nur.repos.rycee.firefox-addons; [
ublock-origin
darkreader
];
};
work = {
id = 1;
extensions.packages = with pkgs.nur.repos.rycee.firefox-addons; [
ublock-origin
bitwarden
multi-account-containers
];
settings = {
"browser.startup.homepage" = "https://company-portal.com";
};
};
banking = {
id = 2;
# Minimal extensions for security
extensions.packages = with pkgs.nur.repos.rycee.firefox-addons; [
ublock-origin
];
settings = {
"privacy.resistFingerprinting" = true;
};
};
};Launch specific profile: firefox -P work
Bookmarks
profiles.default = {
bookmarks = [
{
name = "NixOS";
toolbar = true;
bookmarks = [
{ name = "Home Manager Options"; url = "https://nix-community.github.io/home-manager/options.xhtml"; }
{ name = "NixOS Search"; url = "https://search.nixos.org"; }
];
}
{
name = "GitHub";
url = "https://github.com";
}
];
};Troubleshooting
Extensions Not Installing
-
Check NUR is properly configured:
bashnix eval .#nixosConfigurations.mandaloriano.config.home-manager.users.edoardo.programs.firefox.profiles.default.extensions.packages -
Verify overlay is loaded:
bashnix repl > :lf . > pkgs.nur.repos.rycee.firefox-addons.ublock-origin -
Update flake lock:
bashsudo nix flake update nur
Settings Not Applying
- Settings only apply to new profiles or on first run
- To reset: delete
~/.mozilla/firefox/*.default/prefs.js - Use
force = truein search config to override manual changes
Profile Conflicts
If you have existing Firefox profiles:
# Backup existing profile
cp -r ~/.mozilla/firefox ~/.mozilla/firefox.bak
# Remove to let Home Manager create fresh
rm -rf ~/.mozilla/firefox
# Rebuild
sudo nixos-rebuild switchDark Mode Not Working on Websites
The darkreader extension handles this better than Firefox’s native settings. Ensure it’s installed and enabled.
Build Errors
# Check for syntax errors
nix flake check
# Build without switching (safer)
sudo nixos-rebuild build
# View detailed errors
sudo nixos-rebuild switch --show-traceQuick Reference
| Task | Command/Location |
|---|---|
| Apply changes | sudo nixos-rebuild switch |
| Update NUR | sudo nix flake update nur |
| Firefox config | ~/.mozilla/firefox/ |
| List extensions | Browse NUR repo on GitHub |
| Test profile | firefox -P profilename |
| about:config | Type in Firefox URL bar |