base review
`base` 3.0.0 is a small CommonJS foundation for plugin-based Node applications from the Assemble and Generate toolchain. An instance combines a `cache-base` key-value store with immediate plugin execution, named-plugin deduplication, hidden properties, type markers, and manual parent links. Our Node 22 check loaded it through both `require()` and ESM import, but found no TypeScript declarations and could not produce a browser bundle. The current package was released in 2018, and its source disagrees with parts of the generated README, including the documented `Base.extend` call.
`base` 3.0.0 took 3.1 seconds and 2 MB in our sandbox, but its last release dates to 2018 and its README contains APIs missing from the package. Keep it for compatibility with old Toolkit plugins; do not select it as the core of a new Node application.
We installed it
| Install | ✓ · 3.1s | 32 packages on disk · 2 MB |
| Import | ✓ | ESM import works · require() works · CommonJS package |
| Browser | n/a | could not be bundled for the browser (Node-only code, most likely) |
| Types | — | no TypeScript types found |
| Known vulns | 0 | 0 critical · 0 high · 0 moderate · 0 low (npm audit) |
Answers from our run
Does base install cleanly?
Yes. In a fresh container with an empty cache, npm install base finished in 3 seconds, leaving 32 packages and 2 MB on disk. npm audit reported no known vulnerabilities.
Can base run in a browser?
Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.
Does base work with both ESM and CommonJS?
Yes. Both import 'base' and require('base') worked in Node 22 in our run. The package is published as CommonJS.
Does base include TypeScript types?
No type declarations were found in our install, so TypeScript users need their own declarations.
base or dot-prop: which should you use?
dot-prop: Choose it when the requirement is limited to reading and writing nested keys on plain objects. base 3.0.0 took 3.1 seconds and 2 MB in our sandbox, but its last release dates to 2018 and its README contains APIs missing from the package.
When should you not use base?
You are choosing foundations for a new Node application; npm shows no release since March 2018 and the repository's last push was in October 2022.
Use it if
- An existing Assemble-era application already passes mutable Base instances through `baseplugin` modules.
- You must keep compatibility with plugins that call `use`, `define`, `is`, or `isRegistered` on the host object.
- A migration needs a temporary adapter around the namespaced `cache-base` store and Base's parent-chain lookup.
- You are diagnosing why an old dependency installs `base` and need examples that match version 3.0.0 source code.
- You are choosing foundations for a new Node application; npm shows no release since March 2018 and the repository's last push was in October 2022.
- You need first-party TypeScript declarations; our package inspection found none.
- You intend to follow the README's inheritance sample; `Base.extend` is not present in the 3.0.0 export.
- The object must run in a browser; esbuild could not bundle our test import for a browser target.
- You only want hooks or nested object access; focused packages avoid Base's constructor-level plugin list and mutable all-in-one host object.
Setup reality
Our fresh install of base 3.0.0 completed in 3.1 seconds inside Node 22 Bookworm. It produced 32 installed packages occupying 2 MB, while base itself is 44 KB unpacked and declares 5 direct dependencies with no peers. npm audit returned 0 known vulnerabilities. The distribution is CommonJS without an exports map; require() and ESM import both succeeded. No TypeScript types ship in the package, and its engine floor still says Node 6 or newer.
There are no credentials, environment variables, or config files to prepare. The first constructor argument seeds the inherited store, the second populates options, and ordinary set calls write beneath the active namespace. The default namespace is cache; Base.namespace('settings') creates a separate constructor whose values appear under settings. Version 3 uses native class inheritance, so class App extends Base is the working extension path. The README's Base.extend sample belongs to older code.
Plugins execute during use, receive the same instance as this and as their first argument, and can change any exposed state. A string name makes use skip later registrations under that name. Calling isRegistered(name) also records the name unless its second argument is false, an easy way for a harmless check to suppress the real plugin. Static Base.use stores callbacks in the constructor closure and applies them to every later instance, so tests sharing a process need explicit isolation.
The base getter walks manually assigned parent links until it reaches the first object. The implementation has no circular-reference guard. Our browser-target build failed, which fits the package's server-side design and Node dependency chain. Before forcing version 3 into a lockfile, use npm ls base to identify the old framework that owns it; replacing or upgrading that parent is usually the safer boundary.
Patterns
Build a host with initial state construct-host
const Base = require('base');
const app = new Base({ ready: false }, { mode: 'test' });
app.set('ready', true);
console.log(app.get('ready'), app.options.mode);Version 3 places stored values under the default `cache` namespace; the options object stays on `app.options`.
Store a value by dotted path write-nested-key
const Base = require('base');
const app = new Base();
app.set('http.port', 3000);
console.log(app.get('http.port'));
console.log(app.cache.http.port);`set` comes from `cache-base`; dotted paths work there even though Base's own `define` method does not accept them.
Move stored data to a named property create-namespace
const Base = require('base');
const Settings = Base.namespace('settings');
const app = new Settings();
app.set('db.host', 'db.internal');
console.log(app.settings.db.host);`namespace` returns a new constructor, and that constructor keeps its own static-plugin callback list.
Apply a plugin to one instance install-plugin
const Base = require('base');
const app = new Base();
app.use(function addClock(host) {
host.define('now', () => Date.now());
});
console.log(app.now());The callback runs at once. Base binds `this` to the host and also passes that host as the first argument.
Prevent duplicate plugin execution name-plugin
app.use('metrics', host => host.define('metric', 'requests'));
app.use('metrics', () => { throw new Error('skipped'); });A string name is recorded before the first callback runs; any later `use` with that same name returns without executing.
Inspect registration without reserving the name check-plugin
console.log(app.isRegistered('search', false));
app.use('search', host => host.define('search', value => value));
console.log(app.isRegistered('search', false));The second argument must be `false` for a read-only check. The default call records the name and emits `plugin`.
Extend the version 3 class subclass-base
const Base = require('base');
class WorkerApp extends Base {
constructor(options) {
super({}, options);
this.is('worker');
}
}Native class inheritance matches 3.0.0. The generated README's `Base.extend` call is absent from this release.
Resolve the first parent object reach-root-host
const root = new Base();
root.set('id', 'root');
const child = new Base();
child.parent = root;
console.log(child.base.get('id'));You assign `parent` manually. Circular parent links recurse without a guard and can exhaust the call stack.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| dot-prop | npm | Choose it when the requirement is limited to reading and writing nested keys on plain objects. |
| cache-base | npm | Choose it to preserve Base's underlying namespaced store without taking its plugin host. |
| tapable | npm | Choose it for explicit named hook types in a Node framework or build tool. |
| hookable | npm | Choose it when async hooks, removal, and maintained modern packaging matter. |
More web backend guides
urllib3 · requests · ws · anyio · httpx · undici · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

