mrkeyoor.com_
Sun 20 Sept 17:48 UTC
npmWeb Backendupdated 20 Sept 2026

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.

Verdict

`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

Lab card: what happened when we installed baseScreenshot of base documentation
Install✓ · 3.1s32 packages on disk · 2 MB
ImportESM import works · require() works · CommonJS package
Browsern/acould not be bundled for the browser (Node-only code, most likely)
Typesno TypeScript types found
Known vulns00 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.

API stability2/5Version 3.0.0 has stayed unchanged since March 2018, which makes its actual runtime surface predictable for locked legacy applications. That stability is undercut by a documented major-version mismatch: the README still directs users to `Base.extend`, while the installed class has no such static method. The current source supports standard `extends`, immediate `use`, `define`, type flags, namespaces, and parent lookup.
Docs2/5The repository README lists each public method and gives examples for plugins, type markers, namespaces, hidden properties, and root-object traversal. It was generated in March 2018 and mixes current version 3 behavior with older calls such as `Base.extend` and root-level cache examples that do not match the installed default namespace. Source inspection is required before copying its most consequential examples.
Maintenance1/5npm dates version 3.0.0 to March 30, 2018, and GitHub reports the repository's last push on October 28, 2022. The repository is not archived and currently reports 13 issues and pull requests, yet the package has neither a newer release nor a deprecation notice. That combination leaves maintainers of downstream code to discover stale documentation and compatibility limits themselves.
Ecosystem2/5The npm downloads endpoint counted 9,932,307 downloads in the latest completed week, while GitHub reports 105 stars. The README ties Base to Assemble, Generate, Update, Verb, and packages carrying the `baseplugin` keyword, so much of that traffic can come from established dependency trees. It provides no bundled types, browser path, or current framework integration that would make those downloads evidence for new adoption.

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.
Skip it if

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

PackageRegistryPick it when
dot-propnpmChoose it when the requirement is limited to reading and writing nested keys on plain objects.
cache-basenpmChoose it to preserve Base's underlying namespaced store without taking its plugin host.
tapablenpmChoose it for explicit named hook types in a Node framework or build tool.
hookablenpmChoose 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.