Back to KB
Difficulty
Intermediate
Read Time
8 min

Package Next.js App as Nix Derivation and deploy as Service on NixOS

By Codcompass Team··8 min read

Immutable Next.js Deployments on NixOS: A Flake-Based Service Architecture

Current Situation Analysis

Modern Next.js applications demand deployment strategies that guarantee consistency across development, staging, and production. Traditional approaches often rely on Docker containers or CI/CD pipelines that assemble artifacts dynamically. While functional, these methods introduce drift: Docker images can vary based on base layer updates, and script-based deployments may fail to capture implicit dependencies or environment nuances.

The core pain point is reproducibility. When a Next.js app includes Server-Side Rendering (SSR), API routes, or Middleware, the build output becomes complex. Developers frequently encounter "works on my machine" issues where the production environment differs subtly from the build environment, leading to runtime failures that are difficult to debug.

Nix offers a solution by treating the application as a derivation—a deterministic build instruction that produces a bit-for-bit identical output given the same inputs. By leveraging output: "standalone" in Next.js and packaging the result as a Nix derivation, you eliminate dependency drift entirely. The application, its Node.js runtime, and all npm dependencies are captured in a single, immutable store path. This approach is often overlooked because developers assume Nix is only for system configuration, not application packaging. However, Nix's buildNpmPackage function provides a robust mechanism for bundling Node.js applications with precise control over the build lifecycle.

WOW Moment: Key Findings

The following comparison highlights the operational advantages of using a Nix derivation over traditional containerization for Next.js services.

ApproachReproducibility GuaranteeArtifact SizeDependency DriftRollback Complexity
Docker ContainerLow (Base image updates cause drift)Large (Includes OS layers, unused deps)High (npm install varies by cache/time)Manual image tagging required
PM2 / Systemd ScriptNone (Relies on host environment)Minimal (Source + node_modules)Critical (Host node version/npm version matters)Manual file replacement
Nix DerivationAbsolute (Hash-based immutability)Optimized (Only required deps included)Zero (Locked via npmDepsHash)Atomic switch via nixos-rebuild

Why this matters: The Nix approach ensures that the binary running in production is mathematically identical to the binary built locally. The npmDepsHash mechanism locks the dependency tree, preventing supply-chain surprises. Furthermore, rolling back a deployment is as simple as reverting the flake input and rebuilding, with zero risk of partial updates.

Core Solution

This section outlines the architecture for packaging a Next.js application as a Nix derivation and exposing it as a managed service on NixOS. The solution uses a flake-based workflow to ensure portability and version control.

1. Configure Next.js Standalone Output

Next.js must be configured to generate a standalone output. This mode creates a minimal production bundle containing only the necessary files to run the server, excluding development dependencies and source code.

File: next.config.ts

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  // Enables the standalone output mode required for Nix packaging.
  // This generates a .next/standalone directory with a self-contained server.
  output: "standalone",
};

export default nextConfig;

Rationale: The standalone output is mandatory. Without it, the build produces a structure that includes the entire node_modules directory and source files, which defeats the purpose of Nix's dependency management and results in bloat

🎉 Mid-Year Sale — Unlock Full Article

Base plan from just $4.99/mo or $49/yr

Sign in to read the full article and unlock all 635+ tutorials.

Sign In / Register — Start Free Trial

7-day free trial · Cancel anytime · 30-day money-back