npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@luxmargos/ensure-hosts

v0.1.4

Published

CLI for managing hosts file entries from YAML profiles.

Downloads

794

Readme

@luxmargos/ensure-hosts

Manage local hosts-file entries on macOS, Linux, and Windows from small YAML profiles.

ensure-hosts expands a YAML file into hosts-file records, removes stale records for the same domains when requested, and appends the current records. It is useful for local development domains such as api.myapp.test, admin.myapp.test, and other repeatable project setup.

Why use it?

  • Keep project hostnames in versioned YAML instead of editing /etc/hosts by hand.
  • Re-run the same command safely when project IPs or domains change.
  • Preview changes before writing with --dry-run.
  • Remove a profile's entries when you no longer need them.
  • Share one base config plus project-specific configs.

Requirements

  • Node.js 20 or newer
  • Permission to write the system hosts file when not using --dry-run

Default hosts-file locations:

  • Linux/macOS: /etc/hosts
  • Windows: %SystemRoot%\System32\drivers\etc\hosts

Install

npm install -g @luxmargos/ensure-hosts

Then check the CLI is available:

ensure-hosts --version

Quick start

  1. Create a config file, for example hosts.local.yaml. You can use either the subdomains style or the flat style — both produce the same records:

    Subdomains style — group children under a parent domain:

    profile: MYAPP_LOCAL
    hosts:
      - domain: myapp.test
        address: 127.0.0.1
        children:
          - api
          - admin

    Flat style — list every domain side by side at the top level:

    profile: MYAPP_LOCAL
    hosts:
      - domain: myapp.test
        address: 127.0.0.1
      - domain: api.myapp.test
        address: 127.0.0.1
      - domain: admin.myapp.test
        address: 127.0.0.1
  2. Preview what would be written:

    ensure-hosts --config ./hosts.local.yaml --dry-run
  3. Apply the changes:

    ensure-hosts --config ./hosts.local.yaml

    On macOS and Windows, the CLI can prompt for administrator permission when needed. On Linux, run with sudo if your user cannot write /etc/hosts:

    sudo ensure-hosts --config ./hosts.local.yaml

The example above writes records like:

# MYAPP_LOCAL
127.0.0.1 myapp.test
# MYAPP_LOCAL
127.0.0.1 api.myapp.test
# MYAPP_LOCAL
127.0.0.1 admin.myapp.test

Common commands

# Use one config
ensure-hosts --config ./hosts.local.yaml

# Layer multiple configs
ensure-hosts --config ./base.yaml --config ./project.yaml

# Preview the final hosts file without writing
ensure-hosts --config ./hosts.local.yaml --dry-run

# Print the expanded records only
ensure-hosts --config ./hosts.local.yaml --print-records

# Remove entries managed by rewrite:true records
ensure-hosts --config ./hosts.local.yaml --remove

# Remove every domain listed by the config, including rewrite:false records
ensure-hosts --config ./hosts.local.yaml --remove-force

Configuration reference

A config file must be .yaml or .yml and contain:

profile: PROFILE_NAME
hosts:
  - domain: some.domain.test
    address: 192.168.1.111
    rewrite: true
    skipSelf: false
    children:
      - sitea
      - domain: siteb
        address: ::1

Fields:

| Field | Required? | Description | | --- | --- | --- | | profile | Yes | Label written as a comment above generated entries, for example # MYAPP_LOCAL. | | hosts | Yes | Array of host entries. | | domain | Yes | Domain name. Inside children, this can be a relative subdomain such as api. | | address | For records you want written | IPv4 or IPv6 address. Children inherit the parent address unless they set their own. | | rewrite | No | Whether existing entries for the same domain may be cleaned before appending. Defaults to true. Children inherit the parent value. | | skipSelf | No | Skip writing this node while still processing its children. Defaults to false. | | children | No | Nested subdomains as strings or full objects. |

Subdomains

Child strings inherit the parent address and rewrite value:

profile: LOCAL
hosts:
  - domain: example.test
    address: 127.0.0.1
    children:
      - api
      - admin

This writes:

  • example.test
  • api.example.test
  • admin.example.test

If a child already contains the full parent domain, it is not duplicated. For example, api.example.test stays api.example.test.

As a flat list

If you'd rather spell every domain out instead of using children:, you can list them side by side at the top level. The result is the same as the nested form above:

profile: LOCAL
hosts:
  - domain: example.test
    address: 127.0.0.1
  - domain: api.example.test
    address: 127.0.0.1
  - domain: admin.example.test
    address: 127.0.0.1

This is handy when you're building the config from a script, or when you simply prefer reading a flat list. address, rewrite, and skipSelf can still be set on any entry.

skipSelf example

Use skipSelf: true when you only want child records:

profile: LOCAL
hosts:
  - domain: example.test
    address: 127.0.0.1
    skipSelf: true
    children:
      - api
      - admin

This writes api.example.test and admin.example.test, but not example.test.

How rewriting works

By default, rewrite is true.

With rewrite: true, ensure-hosts:

  1. Removes existing hosts entries for the same domain.
  2. Removes stale adjacent # PROFILE_NAME comments left by previous runs.
  3. Appends the current generated entry when an address is available.

With rewrite: false, ensure-hosts:

  1. Leaves existing entries for the same domain untouched.
  2. Appends the generated entry only if that domain is not already present.

Entries without an effective address are not written. If their effective rewrite value is true, matching existing entries can still be cleaned.

Generated entries use one # PROFILE_NAME comment per contiguous managed block by default. Use --repeat-profile-comments when you want the profile comment repeated before every generated hosts line.

Remove mode

Use remove mode when you want to uninstall entries from a profile instead of ensuring them.

ensure-hosts --config ./hosts.local.yaml --remove
ensure-hosts --config ./hosts.local.yaml --remove-force
ensure-hosts --config ./hosts.local.yaml --remove --dry-run
  • --remove removes domains whose effective rewrite value is true. Domains marked rewrite: false are left untouched.
  • --remove-force removes every domain listed by the config, including rewrite: false domains.

--remove and --remove-force cannot be used together, and neither can be combined with --print-records.

Environment variables

The CLI automatically loads .env from the current working directory. Missing .env files are ignored by default.

Use --env-file <path> if your dotenv file is not named .env. The option is repeatable and files are loaded in order:

ensure-hosts --env-file .env --env-file .env.local --config ./hosts.yaml

By default, later dotenv files overwrite existing values, including shell environment variables and values from earlier dotenv files. Use respect mode to keep existing values:

ensure-hosts --env-override respect --env-file .env --env-file .env.local --config ./hosts.yaml

You can also set the mode with ENSURE_HOSTS_ENV_OVERRIDE=overwrite or ENSURE_HOSTS_ENV_OVERRIDE=respect. CLI options take precedence over environment variables.

Missing dotenv files are skipped by default. Use --env-file-missing error or ENSURE_HOSTS_ENV_FILE_MISSING=error to fail when an expected dotenv file does not exist.

You can provide config paths with ENSURE_HOSTS_CONFIG instead of --config:

ENSURE_HOSTS_CONFIG=./hosts.local.yaml,./another.yaml

You can also override the hosts file path, which is useful for tests or custom workflows:

ENSURE_HOSTS_HOSTS_FILE=./tmp-hosts

To disable macOS/Windows elevation prompts:

ENSURE_HOSTS_NO_ELEVATE=true

YAML config files support Docker Compose-like variable interpolation after dotenv files are loaded:

profile: "${PROFILE_NAME:-LOCAL}"
hosts:
  - domain: "${APP_DOMAIN}"
    address: "${APP_ADDRESS-127.0.0.1}"

Supported forms:

  • ${VAR_NAME} expands to the environment value. If missing, it expands to an empty string and prints an [ensure-hosts] warning.
  • ${VAR_NAME:-default} uses default when the variable is unset or empty.
  • ${VAR_NAME-default} uses default only when the variable is unset.

CLI options

--config <path>      YAML/YML config file path (repeatable)
--env-file <path>    dotenv file path (default: .env, repeatable)
--env-override <mode>  dotenv collision mode: overwrite|respect (default: overwrite)
--env-file-missing <mode>  missing dotenv mode: ignore|error (default: ignore)
--hosts-file <path>  override hosts file path
--dry-run            print rewritten hosts content without writing
--print-records      print expanded records and exit
--repeat-profile-comments  repeat profile comment before every generated host line
--remove             remove rewrite:true domains (respects rewrite:false)
--remove-force       remove all listed domains, including rewrite:false
--no-elevate         disable macOS/Windows privilege prompt
--help               show help
--version            show version

Notes:

  • On Linux, --no-elevate is effectively a no-op because Linux does not use an in-process elevation prompt. Run the command with sudo when needed.
  • Use --hosts-file or ENSURE_HOSTS_HOSTS_FILE to test against a temporary file instead of the real hosts file.

Development

Install dependencies:

npm install

Run checks:

npm test
npm run typecheck
npm run build

The repository also includes a Docker-based Linux test harness (Dockerfile.linux-test and compose.linux-test.yaml). These files are for testing only, not production.

# Run the unit test suite in a Linux container
docker compose -f compose.linux-test.yaml run --rm test

# Typecheck and build
docker compose -f compose.linux-test.yaml run --rm typecheck
docker compose -f compose.linux-test.yaml run --rm build

# Exercise CLI scenarios
docker compose -f compose.linux-test.yaml run --rm dry-run
docker compose -f compose.linux-test.yaml run --rm print-records
docker compose -f compose.linux-test.yaml run --rm root-write
docker compose -f compose.linux-test.yaml run --rm etc-hosts-write
docker compose -f compose.linux-test.yaml run --rm non-root-fail
docker compose -f compose.linux-test.yaml run --rm remove

The root-write, non-root-fail, and remove services use --hosts-file /tmp/test-hosts, so the real /etc/hosts is not modified. The etc-hosts-write service writes to the container's ephemeral /etc/hosts, not your host machine.

License

MIT