Skip to main content
Bun implements the standard Console API with enhanced formatting, colors, and object inspection. It’s compatible with Node.js and browsers.

Basic Logging

console.log()

Log messages to stdout:
console.log("Hello");
console.log("Number:", 42);
console.log("Object:", { name: "Alice", age: 30 });
console.log("Array:", [1, 2, 3]);

console.error()

Log errors to stderr:
console.error("Error occurred");
console.error("Error:", new Error("Something went wrong"));

console.warn()

Log warnings to stderr:
console.warn("Deprecated function");
console.warn("Warning:", "This will be removed in v2.0");

console.info()

Log informational messages:
console.info("Server started");
console.info("Port:", 3000);

console.debug()

Log debug messages:
console.debug("Debug info:", { state: "active", count: 42 });

Formatting

Format Specifiers

// %s - String
console.log("Hello %s", "World");

// %d or %i - Integer
console.log("Count: %d", 42);

// %f - Float
console.log("Pi: %f", 3.14159);

// %o - Object
console.log("Data: %o", { x: 1, y: 2 });

// %O - Object (detailed)
console.log("Details: %O", { x: 1, y: 2 });

// %c - CSS styling (in browsers)
console.log("%cStyled text", "color: blue; font-weight: bold");

Multiple Arguments

console.log("User", user, "logged in at", timestamp);

Object Inspection

Default Inspection

const obj = {
  name: "Alice",
  age: 30,
  address: {
    city: "NYC",
    zip: "10001",
  },
};

console.log(obj);
// {
//   name: "Alice",
//   age: 30,
//   address: { city: "NYC", zip: "10001" }
// }

Deep Inspection

Control inspection depth:
const nested = {
  level1: {
    level2: {
      level3: {
        level4: { value: 42 },
      },
    },
  },
};

console.log(nested);
// Default depth: 2 levels
Set depth with environment variable:
# Show 4 levels deep
bun --console-depth=4 script.ts
Or in bunfig.toml:
[console]
depth = 4

Arrays

const arr = [1, 2, 3, 4, 5];
console.log(arr);
// [1, 2, 3, 4, 5]

// Large arrays are truncated
const large = Array.from({ length: 1000 }, (_, i) => i);
console.log(large);
// [0, 1, 2, ... 997, 998, 999]

Functions

function greet(name: string) {
  return `Hello ${name}`;
}

console.log(greet);
// [Function: greet]

const arrow = (x: number) => x * 2;
console.log(arrow);
// [Function: arrow]

Classes

class User {
  constructor(public name: string) {}
  
  greet() {
    return `Hello ${this.name}`;
  }
}

const user = new User("Alice");
console.log(user);
// User { name: "Alice" }

Grouping

console.group()

Create collapsible groups:
console.group("User Details");
console.log("Name:", "Alice");
console.log("Age:", 30);
console.group("Address");
console.log("City:", "NYC");
console.log("Zip:", "10001");
console.groupEnd();
console.groupEnd();

// User Details
//   Name: Alice
//   Age: 30
//   Address
//     City: NYC
//     Zip: 10001

console.groupCollapsed()

Create collapsed groups:
console.groupCollapsed("Debug Info");
console.log("Timestamp:", Date.now());
console.log("Memory:", process.memoryUsage());
console.groupEnd();

Tables

console.table()

Display data as a table:
const users = [
  { name: "Alice", age: 30, city: "NYC" },
  { name: "Bob", age: 25, city: "LA" },
  { name: "Charlie", age: 35, city: "Chicago" },
];

console.table(users);
// ┌─────────┬─────────┬─────┬─────────┐
// │ (index)   │ name    │ age │ city    │
// ├─────────┼─────────┼─────┼─────────┤
// │ 0         │ 'Alice' │ 30  │ 'NYC'   │
// │ 1         │ 'Bob'   │ 25  │ 'LA'    │
// │ 2         │ 'Charlie' │ 35 │ 'Chicago' │
// └─────────┴─────────┴─────┴─────────┘

Select Columns

const users = [
  { name: "Alice", age: 30, city: "NYC", country: "USA" },
  { name: "Bob", age: 25, city: "LA", country: "USA" },
];

// Only show name and age columns
console.table(users, ["name", "age"]);

Objects as Tables

const obj = {
  name: "Alice",
  age: 30,
  city: "NYC",
};

console.table(obj);
// ┌───────┬────────┐
// │ (index) │ Values │
// ├───────┼────────┤
// │ name    │ 'Alice' │
// │ age     │ 30      │
// │ city    │ 'NYC'   │
// └───────┴────────┘

Timing

console.time()

Measure execution time:
console.time("operation");

// Do some work
for (let i = 0; i < 1000000; i++) {
  Math.sqrt(i);
}

console.timeEnd("operation");
// operation: 15.234ms

console.timeLog()

Log intermediate times:
console.time("task");

// Step 1
processStep1();
console.timeLog("task", "Step 1 complete");
// task: 10ms Step 1 complete

// Step 2
processStep2();
console.timeLog("task", "Step 2 complete");
// task: 25ms Step 2 complete

console.timeEnd("task");
// task: 30ms

Multiple Timers

console.time("total");
console.time("fetch");
await fetchData();
console.timeEnd("fetch");

console.time("process");
await processData();
console.timeEnd("process");

console.timeEnd("total");

Counting

console.count()

Count function calls:
function processItem(item: string) {
  console.count("processItem");
  // Process item
}

processItem("a");
// processItem: 1
processItem("b");
// processItem: 2
processItem("c");
// processItem: 3

console.countReset()

Reset counter:
console.count("requests");
console.count("requests");
// requests: 2

console.countReset("requests");
console.count("requests");
// requests: 1

Labeled Counters

function handleRequest(type: string) {
  console.count(type);
}

handleRequest("GET");  // GET: 1
handleRequest("POST"); // POST: 1
handleRequest("GET");  // GET: 2

Assertions

console.assert()

Log error if assertion fails:
const value = 5;
console.assert(value > 0, "Value must be positive");
// No output (assertion passed)

console.assert(value > 10, "Value must be greater than 10");
// Assertion failed: Value must be greater than 10

With Objects

const user = { name: "Alice", age: 30 };
console.assert(user.age >= 18, "User must be adult", { user });

Stack Traces

console.trace()

Print stack trace:
function outer() {
  function inner() {
    console.trace("Trace:");
  }
  inner();
}

outer();
// Trace:
//   at inner (file.ts:3:13)
//   at outer (file.ts:5:3)
//   at <anonymous> (file.ts:8:1)

Clearing

console.clear()

Clear console (terminal only):
console.log("Message 1");
console.log("Message 2");
console.clear(); // Clears terminal
console.log("Message 3");

Colors

Bun automatically colors output in terminals:
// Errors in red
console.error("Error message");

// Warnings in yellow
console.warn("Warning message");

// Objects with syntax highlighting
console.log({ key: "value", num: 42 });
Disable colors:
NO_COLOR=1 bun script.ts
Or:
bun script.ts --no-color

Custom Inspection

inspect Symbol

class User {
  constructor(public name: string, private password: string) {}
  
  [Symbol.for("nodejs.util.inspect.custom")]() {
    return `User { name: ${this.name} }`;
  }
}

const user = new User("Alice", "secret123");
console.log(user);
// User { name: Alice }

toJSON()

class Point {
  constructor(public x: number, public y: number) {}
  
  toJSON() {
    return { x: this.x, y: this.y };
  }
}

const p = new Point(10, 20);
console.log(p);
// Point { x: 10, y: 20 }

Best Practices

  1. Use appropriate log levels
    console.debug("Verbose debug info");
    console.log("Normal output");
    console.warn("Warning message");
    console.error("Error occurred");
    
  2. Group related logs
    console.group("API Request");
    console.log("URL:", url);
    console.log("Method:", method);
    console.log("Headers:", headers);
    console.groupEnd();
    
  3. Use timers for performance
    console.time("database-query");
    await db.query(sql);
    console.timeEnd("database-query");
    
  4. Table for structured data
    console.table(results);
    
  5. Assertions for debugging
    console.assert(user.id, "User ID is required");
    

Production Logging

For production apps, consider using a logging library:
import { createLogger } from "some-logger";

const logger = createLogger({
  level: process.env.LOG_LEVEL || "info",
  format: "json",
});

logger.info("Server started", { port: 3000 });
logger.error("Request failed", { error, url });

Platform Differences

Bun vs Node.js

  • Colors: Bun has better default colors
  • Performance: Bun’s console is faster
  • Depth: Bun defaults to depth 2, Node to unlimited

Bun vs Browsers

  • Streams: Bun writes to stdout/stderr, browsers to DevTools
  • Styling: CSS styling (%c) only works in browsers
  • Persistence: Browser console persists between reloads

API Reference

Logging Methods

console.log(...args: any[]): void
console.error(...args: any[]): void
console.warn(...args: any[]): void
console.info(...args: any[]): void
console.debug(...args: any[]): void

Grouping

console.group(label?: string): void
console.groupCollapsed(label?: string): void
console.groupEnd(): void

Tables

console.table(data: any, columns?: string[]): void

Timing

console.time(label?: string): void
console.timeLog(label?: string, ...args: any[]): void
console.timeEnd(label?: string): void

Counting

console.count(label?: string): void
console.countReset(label?: string): void

Other

console.assert(condition: boolean, ...args: any[]): void
console.trace(...args: any[]): void
console.clear(): void

Build docs developers (and LLMs) love