https://github.com/gadicc/node-hosts-so-easy
Safe, parallel API for manipulating /etc/hosts.
https://github.com/gadicc/node-hosts-so-easy
Last synced: 3 months ago
JSON representation
Safe, parallel API for manipulating /etc/hosts.
- Host: GitHub
- URL: https://github.com/gadicc/node-hosts-so-easy
- Owner: gadicc
- License: mit
- Created: 2017-12-07T12:44:11.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2026-03-05T15:42:45.000Z (3 months ago)
- Last Synced: 2026-03-05T18:44:40.065Z (3 months ago)
- Language: JavaScript
- Homepage: https://www.npmjs.com/package/hosts-so-easy
- Size: 1.14 MB
- Stars: 8
- Watchers: 1
- Forks: 3
- Open Issues: 30
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# hosts-so-easy
*Safe, parallel API for manipulating /etc/hosts*
[](https://www.npmjs.com/package/hosts-so-easy)
[](https://circleci.com/gh/gadicc/node-hosts-so-easy)
[](https://coveralls.io/github/gadicc/node-hosts-so-easy?branch=master)

[](https://snyk.io/test/github/gadicc/hosts-so-easy?targetFile=package.json)
[](https://david-dm.org/gadicc/node-hosts-so-easy)
[](http://commitizen.github.io/cz-cli/)
[](https://github.com/semantic-release/semantic-release)
Copyright (c) 2017 by Gadi Cohen. Released under the MIT license.
Note: we support and run tests against latest Node, and Node v10 LTS (as of 2021-01-10).
## Features
* [X] Built for safe and concurrent / parallel use.
* [X] Add/remove funcs are (optionally) "use and forget" - no callbacks required.
* [X] Preserves formatting (comments & whitespace choices) - see sample below.
* [X] Changes are batched, atomic write is debounced 500ms (by default).
* [X] Optionally keeps new entries in a separate "header" block.
## Usage
```js
import Hosts from 'hosts-so-easy';
const hosts = new Hosts();
// hosts file is written once at the end
hosts.add('192.168.0.1', 'www');
hosts.add('192.168.1.1', [ 'mongo', 'db' ]);
// this is completely safe, only one write occurs at the end.
for (let i = 2; i < 10; i++)
hosts.add('192.168.0.'+i, 'host'+i);
// can remove individual hosts, all hosts for an IP, or a host from any IP
hosts.remove('192.168.2.1', '*');
hosts.remove('192.168.3.1', 'vhost20');
hosts.remove('192.168.4.1', [ 'mongo', 'db' ]);
hosts.remove('*', 'unwantedHost');
hosts.remove('*', [ 'unwantedHost1', 'unwantedHost2' ]);
// callback/promise after all changes synced in a single write
await hosts.updateFinish();
hosts.updateFinish().then(function() { ... }).catch(function(err) { ... });
hosts.updateFinish(callback);
hosts.on('updateFinish', callback);
hosts.once('updateFinish', callback);
```
## Options
```js
const hosts = new Hosts({
// Write the new contents to a temporary file first and rename afterwards
// instantly to avoid conflicts with other writers. You'll know if you
// need to turn this off (special filesystems, etc). Either way, we always
// check to avoid concurrent writes within the library.
atomicWrites: false, // default: true
// How long to wait after *last* add/remove before writing the file,
// to write the file once even after performing many operations.
// Even with a small value, we'll check to avoid concurrent writes.
debounceTime: 500, // in ms, default: 500ms
// Maintain a header block and insert new entries there. See sample output
// further down the README for an example.
header: 'Docker hosts', // default: false
// Linux/Mac default: /etc/hosts
// Windows default: C:/Windows/System32/drivers/etc/hosts
hostsFile: '/some/weird/location/hosts',
});
```
## API
### Methods
* `hosts.add(ip, host || [host1,host2])`
For the given IP, add a single host or an array of hosts.
* `hosts.clearQueue()`
If you had a change of heart, and call this in time, nothing will happen :)
* `hosts.on(event, callback)`
`hosts.once(event, callback)`
Run the given callback on every event occurrence, or just once when the event
next occurs. See EVENTS, below.
* `hosts.remove(ip || '*', host || [host1,host2] || '*')`
For the given IP, remove the given host or all the hosts in the array.
Alternatively, give a "host" of `*` to remove the entire line, or an
"ip" of `*` to remove the given host(s) from any IP.
* `hosts.removeHost(host)`
Remove all references of `host`, regardless of which IP it resolves to.
This has the same effect as `hosts.remove('*', host)`.
* `hosts.updateFinish([callback])`
If a callback is given, it's called at the end of the update sequence (see
events, below). If an error occurred, it's provided as the first argument.
If no callback is given, a `Promise` is returned. It resolves after a
successful write, or rejects on failure.
### Events
* `updateStart` - fires at the beginning of update sequence. Hosts file will
be stat'd, read and rewritten.
* `updateFinish` - fires at the end of the above sequence. On failure, the
error will be provided as the first argument (file not found, permission
denied, etc).
## Sample output (formatting preserved)
```js
const hosts = new Hosts({ header: 'optional header' });
```
```
#
# /etc/hosts: static lookup table for host names
#
#
127.0.0.1 localhost.localdomain localhost
::1 localhost.localdomain localhost
# optional header
172.20.0.2 host2
172.20.0.3 host3
192.168.0.2 server2
```
## TODO
* [X] Ability to turn off atomic writes
* [X] Maintain a header block (put hosts in same section)
* [X] EventEmitter for writes
* [X] Validate arguments, throw on invalid
## Wishlist
* [ ] Callback / promise when particular host entry added. Can't think of
any use-case where the 'write' event would not be sufficient, but I'll
add this if you give me a good reason.
* [ ] Mimic preceding whitespace pattern for new entry insertion.
* [X] Better caching for those doing A LOT of work on the file.