hushlog 1.4.0

console logger · zero dependencies

Loud in dev.
Silent in prod.

Styled, scoped output while you build. Nothing once you ship, unless you tell a server to speak. No flags, no build step.

NODE_ENV
console development · 0 lines

Flip the switch. Silence is the default — servers can ask for an exception.

levels

Five levels, five colors

Each level maps to its matching console method, so devtools filtering and stack traces keep working. Color is the only thing hushlog adds.

log() General output
log.info() Informational messages
log.warn() Warnings, deprecations
log.error() Errors, failures
log.success() Confirmations, completed actions
import { log } from "hushlog";

log("Fetching user:", id);
log.warn("Token expiring soon");
log.success("User saved");

scopes

Name the source once

logScope returns a logger with all five levels attached and a prefix baked in, so you never hand-write the module name into a message again.

import { logScope } from "hushlog";

const log = logScope("auth");

log("User signed in:", user);
log.error("Invalid credentials");
console development · 0 lines

filters

Narrow the noise at runtime

setLogFilter decides which prefixes speak, without touching a line of code. Unprefixed logs from the default log always come through — until you silence everything.

console development · 0 lines

groups

Keep a sequence together

logGroup wraps related output in a collapsible block. It is async-aware: the group stays open until your callback resolves, and closes even if the callback throws.

await logGroup("Load config", async () => {
  const config = await fetchConfig();
  log.success("Config loaded:", config);
}, { collapsed: false });
console development · 0 lines

server logs

Production output, terminal only

Server-rendered apps often want production logs where a hosted collector can read them, while the browser stays silent. Mark a scope target: "server" and it survives into production on the server — and only there.

const dbLog = logScope("db", { target: "server" });
const uiLog = logScope("ui"); // dev only, the default

dbLog.error("Query failed:", err); // dev, and production stdout
uiLog("Modal opened"); // dev only
server stdout production · 0 lines

This one is pinned to production, so the switch at the top of the page does not reach it. [ui] is still in the code either way — it just never gets here.

Two switches

The deploy sets HUSHLOG_SERVER=1; the code sets target. Both must agree, so ops can silence production without a code change.

The browser never sees it

HUSHLOG_SERVER is read from process.env only, so bundlers inline it as undefined in client builds. Workers count as browser.

Change it without touching code

setServerLogScopes("db", "auth") overrides every target at once — process-wide, so set it at boot rather than per request. setLogFilter still applies on top.

Before you turn it on

Production output leaves the box for your log store, and nothing is tree-shaken — keep secrets out either way.

environment

It works out what dev means

hushlog checks for development in the order your tooling is likely to report it, then falls back to the host it is running on.

Bundlers

Vite reads import.meta.env.DEV. Next.js, webpack, Bun and Node read process.env.NODE_ENV.

Deno

Reads NODE_ENV when env access is granted, and stays quiet rather than throwing when it is not.

Plain browsers & workers

With no bundler in the picture, a localhost hostname counts as development.

Terminals

Devtools get %c styling; Node TTYs get ANSI color and honour NO_COLOR.

reference

The whole API

log(message?, ...args)

Default logger. .info, .warn, .error and .success share the signature.

logScope(prefix, options?)

Returns a logger that tags every message with [prefix]. target is "dev" or "server", default "dev".

setLogFilter(...prefixes)

Pass prefixes to allow, "*" for everything, or null to silence output entirely.

setServerLogScopes(...prefixes)

Overrides every logger's target, choosing which prefixes reach production server output. No arguments clears it.

logGroup(label, callback, options?)

Groups the callback's output. Options are collapsed, prefix and target. Returns the callback's result.

// Named and default imports both work
import log, { logScope, logGroup, setLogFilter } from "hushlog";

Ships as ESM and CommonJS with hand-written TypeScript types. No dependencies.