Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/cachix/devenv/llms.txt

Use this file to discover all available pages before exploring further.

devenv supports monorepo layouts where multiple services share common configuration — a database, linting rules, shared packages — while each service also maintains its own specific settings. Shared configuration lives in a single devenv.nix file, and each service imports it by reference so there is no duplication.
Monorepo support via absolute imports was introduced in devenv v1.10.
Profiles provide another way to organise environments within a monorepo. They let different configurations activate automatically based on hostname, username, or a CLI flag — useful for team-specific or environment-specific variations on top of the structure described here.

Directory Structure

A typical monorepo layout looks like this:
my-monorepo/
├── shared/
│   └── devenv.nix       # Shared configuration
├── services/
│   ├── api/
│   │   ├── devenv.yaml
│   │   └── devenv.nix
│   └── frontend/
│       ├── devenv.yaml
│       └── devenv.nix

Shared Configuration

Create a shared/devenv.nix file that contains settings every service should inherit — common packages, a shared database, and project-wide Git hooks:
shared/devenv.nix
{ pkgs, ... }: {
  packages = [
    pkgs.curl
    pkgs.jq
  ];

  services.postgres = {
    enable = true;
    initialDatabases = [
      { name = "myapp"; }
    ];
  };

  git-hooks.hooks = {
    prettier.enable = true;
    nixpkgs-fmt.enable = true;
  };
}

Per-Service Configuration

Each service imports the shared config using an absolute import path. Paths starting with / are resolved from the repository root (where .git is located), so they work regardless of which subdirectory the import appears in.

API Service

services/api/devenv.yaml
imports:
  - /shared
services/api/devenv.nix
{ pkgs, ... }: {
  # Node.js for the API
  languages.javascript = {
    enable = true;
    package = pkgs.nodejs_20;
  };

  # API-specific environment variables
  env = {
    API_PORT = "3000";
    SERVICE_NAME = "api";
  };

  # API scripts
  scripts = {
    dev.exec = "npm run dev";
    test.exec = "npm test";
  };
}

Frontend Service

services/frontend/devenv.yaml
imports:
  - /shared
services/frontend/devenv.nix
{ pkgs, ... }: {
  languages.javascript = {
    enable = true;
    package = pkgs.nodejs_20;
  };

  scripts = {
    dev.exec = "npm run dev";
    build.exec = "npm run build";
  };
}

Referencing the Repository Root

When a process needs to cd into a specific subdirectory before running, use config.git.root to get the absolute path to the git repository root. This works correctly regardless of which service directory you run devenv from:
services/api/devenv.nix
{ pkgs, config, ... }: {
  processes.api.exec = {
    exec = "npm run dev";
    cwd = "${config.git.root}/services/api";
  };

  processes.frontend.exec = {
    exec = "npm run dev";
    cwd = "${config.git.root}/services/frontend";
  };
}
This lets you run multiple service processes from a single devenv shell, regardless of which directory you’re currently in.

Working with Individual Services

1

Enter a service environment

Navigate to the service directory and open the shell:
$ cd services/api
$ devenv shell
The API service shell includes everything from shared/devenv.nix (curl, jq, PostgreSQL, Git hooks) merged with its own settings (Node.js 20, API_PORT, SERVICE_NAME).
2

Start the service processes

From inside a service environment, or from the root if you define processes there:
$ devenv up
The frontend service inherits the shared configuration in the same way — you get PostgreSQL and the shared packages automatically, plus the frontend-specific scripts.

Build docs developers (and LLMs) love