Skip to main content
This page documents utility functions available in the Hono application’s src/core/utils/ directory.

Converter utilities

File: apps/hono/src/core/utils/converter.ts

base64ToUint8Array

Converts a base64 encoded string to a Uint8Array. Handles URL-safe base64 encoding by replacing ’-’ with ’+’ and ’_’ with ’/’. Adds necessary padding if missing.
base64String
string
required
The base64 encoded string to convert
Returns: Uint8Array representing the decoded data
apps/hono/src/core/utils/converter.ts
export function base64ToUint8Array(base64String: string): Uint8Array {
  const padding = "=".repeat(
    (4 - (base64String.length % 4)) % 4
  );
  const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/");

  const rawData = atob(base64);
  const outputArray = new Uint8Array(rawData.length);

  for (let i = 0; i < rawData.length; ++i) {
    outputArray[i] = rawData.charCodeAt(i);
  }
  return outputArray;
}
Example usage:
const base64Image = "iVBORw0KGgoAAAANSUhEUgAAAAUA...";
const imageBytes = base64ToUint8Array(base64Image);
const blob = new Blob([imageBytes], { type: 'image/png' });

fileToDataUri

Converts a File object to a data URI.
file
File
required
The File object to convert
Returns: Promise<string> - A data URI representing the file
apps/hono/src/core/utils/converter.ts
export async function fileToDataUri(file: File): Promise<string> {
  const arrayBuffer = await file.arrayBuffer();
  const uint8Array = new Uint8Array(arrayBuffer);
  
  let binaryString = "";
  for (const byte of uint8Array) {
    binaryString += String.fromCharCode(byte);
  }
  
  const base64String = btoa(binaryString);
  const mimeType = file.type || "application/octet-stream";
  return `data:${mimeType};base64,${base64String}`;
}
Example usage:
const file = new File(["hello"], "example.txt", { type: "text/plain" });
const dataUri = await fileToDataUri(file);
console.log(dataUri); // data:text/plain;base64,aGVsbG8=

Network utilities

File: apps/hono/src/core/utils/net.ts

getClientIpAddress

Get the client IP address from request headers. Checks multiple header sources in priority order.
headers
Headers
required
The request headers object
Returns: string | null - The client IP address or null if not found Header priority:
  1. cf-connecting-ip (Cloudflare)
  2. x-forwarded-for (most common)
  3. x-real-ip (Nginx)
  4. x-client-ip (load balancers)
  5. forwarded (RFC 7239 standard)
apps/hono/src/core/utils/net.ts
export function getClientIpAddress(headers: Headers): string | null {
  const cfConnectingIp = headers.get("cf-connecting-ip");
  if (cfConnectingIp) return cfConnectingIp;

  const xForwardedFor = headers.get("x-forwarded-for");
  if (xForwardedFor) return xForwardedFor.split(",")[0].trim();

  const xRealIp = headers.get("x-real-ip");
  if (xRealIp) return xRealIp;

  const xClientIp = headers.get("x-client-ip");
  if (xClientIp) return xClientIp;

  const forwarded = headers.get("forwarded");
  if (forwarded) {
    const match = forwarded.match(/for=([^;,\s]+)/);
    if (match?.[1]) return match[1];
  }

  return null;
}
Example usage:
app.get("/api/location", (c) => {
  const clientIp = getClientIpAddress(c.req.raw.headers);
  return c.json({ ip: clientIp });
});

getClientIpAddressFromContext

Get the client IP address from Hono context using runtime-specific connection info.
c
Context
required
The Hono context object
Returns: Promise<string | null> - The client IP address or null if not found
apps/hono/src/core/utils/net.ts
export async function getClientIpAddressFromContext<
  E extends Env,
  P extends string,
  I extends Input,
>(c: Context<E, P, I>): Promise<string | null> {
  const runtime = getRuntimeKey();
  let connInfo: ConnInfo | null = null;

  if (runtime === "node") {
    const { getConnInfo } = await import("@hono/node-server/conninfo");
    connInfo = getConnInfo(c);
  } else {
    const { getConnInfo } = await import("hono/bun");
    connInfo = getConnInfo(c);
  }

  return connInfo?.remote.address || null;
}
Example usage:
import { getClientIpAddressFromContext } from "@/core/utils/net.js";

app.use("*", async (c, next) => {
  const ip = await getClientIpAddressFromContext(c);
  c.set("clientIp", ip);
  await next();
});

ipAddressHeaders

Constant object containing IP address header names.
apps/hono/src/core/utils/net.ts
export const ipAddressHeaders = {
  cfConnectingIp: "cf-connecting-ip",
  xForwardedFor: "x-forwarded-for",
  xRealIp: "x-real-ip",
  xClientIp: "x-client-ip",
  forwarded: "forwarded",
} as const;

Telemetry utilities

File: apps/hono/src/core/utils/telemetry.ts These utilities help with OpenTelemetry tracing and span management.

getTracer

Get a tracer instance, optionally disabling tracing.
isEnabled
boolean
default:"false"
Whether tracing is enabled
tracer
Tracer
Optional tracer to use instead of the default
Returns: Tracer - A tracer instance or noop tracer
apps/hono/src/core/utils/telemetry.ts
export function getTracer({
  isEnabled = false,
  tracer,
}: {
  isEnabled?: boolean;
  tracer?: Tracer;
} = {}): Tracer {
  if (!isEnabled) return noopTracer;
  if (tracer) return tracer;
  return trace.getTracer(SERVICE_NAME);
}

recordSpan

Wraps a function with a tracer span. Automatically handles errors and span lifecycle.
name
string
required
The name of the span
tracer
Tracer
required
The tracer to use
attributes
Attributes
required
The attributes to set on the span
fn
(span: Span) => Promise<T>
required
The async function to wrap
endWhenDone
boolean
default:"true"
Whether to end the span when the function completes
Returns: Promise<T> - The result of the wrapped function
apps/hono/src/core/utils/telemetry.ts
export function recordSpan<T>({
  name,
  tracer,
  attributes,
  fn,
  endWhenDone = true,
}: {
  name: string;
  tracer: Tracer;
  attributes: Attributes;
  fn: (span: Span) => Promise<T>;
  endWhenDone?: boolean;
}) {
  return tracer.startActiveSpan(name, { attributes }, async (span) => {
    try {
      const result = await fn(span);
      
      if (endWhenDone) {
        span.setStatus({ code: SpanStatusCode.OK });
        span.end();
      }
      
      return result;
    } catch (error) {
      // Record exception and set error status
      if (error instanceof Error) {
        span.recordException({
          name: error.name,
          message: error.message,
          stack: error.stack ?? "",
        });
        span.setStatus({
          code: SpanStatusCode.ERROR,
          message: error.message,
        });
      } else {
        span.setStatus({ code: SpanStatusCode.ERROR });
      }
      
      span.end();
      throw error;
    }
  });
}
Example usage:
import { trace } from "@opentelemetry/api";
import { recordSpan } from "@/core/utils/telemetry.js";

const result = await recordSpan({
  name: "database.query.users",
  tracer: trace.getTracer("api"),
  attributes: {
    "db.operation": "select",
    "db.table": "users",
  },
  fn: async (span) => {
    span.addEvent("Starting query");
    const users = await db.select().from(usersTable);
    span.setAttribute("result.count", users.length);
    return users;
  },
});

flattenAttributes

Recursively flattens nested objects for trace attributes. Converts complex objects into flat key-value pairs suitable for OpenTelemetry.
obj
unknown
required
The object to flatten
config.prefix
string
default:""
Prefix for attribute keys
config.maxDepth
number
default:"3"
Maximum nesting depth to flatten
Returns: Record<string, string> - Flattened attributes
apps/hono/src/core/utils/telemetry.ts
const attributes = flattenAttributes({
  user: {
    id: 123,
    name: "John",
    profile: {
      email: "[email protected]",
      age: 30,
    },
  },
  metadata: {
    items: ["a", "b", "c"],
  },
});

// Result:
// {
//   "user.id": "123",
//   "user.name": "John",
//   "user.profile.email": "[email protected]",
//   "user.profile.age": "30",
//   "metadata.items.0": "a",
//   "metadata.items.1": "b",
//   "metadata.items.2": "c"
// }

flattenAttributesV2

Alternative flattening implementation that handles OpenTelemetry AttributeValue types more strictly.
obj
Record<string, unknown>
required
The object to flatten
prefix
string
default:""
Prefix for attribute keys
Returns: Record<string, AttributeValue> - Flattened attributes with proper types
apps/hono/src/core/utils/telemetry.ts
const attributes = flattenAttributesV2({
  request: {
    method: "POST",
    headers: { "content-type": "application/json" },
    tags: ["api", "v1"],
  },
});

// Result handles arrays and nested objects properly for OTel

noopTracer

A no-operation tracer that does nothing. Useful for disabling tracing without changing code.
apps/hono/src/core/utils/telemetry.ts
export const noopTracer: Tracer = {
  startSpan() { return noopSpan; },
  startActiveSpan(_, arg1, arg2, arg3) {
    if (typeof arg1 === "function") return arg1(noopSpan);
    if (typeof arg2 === "function") return arg2(noopSpan);
    if (typeof arg3 === "function") return arg3(noopSpan);
  },
};

Logger utility

File: apps/hono/src/core/utils/logger.ts The Hono app includes its own logger implementation that integrates with OpenTelemetry.
apps/hono/src/core/utils/logger.ts
import { Logger as CoreLogger } from "@workspace/core/utils/logger";
import { logs } from "@opentelemetry/api-logs";

export const logger = new Logger({
  loggerProvider: logs.getLoggerProvider(),
  // ... configuration
});
The logger supports:
  • Log levels: TRACE, DEBUG, INFO, WARN, ERROR, FATAL
  • Structured logging: Log objects with attributes
  • OpenTelemetry integration: Automatic log export to observability backend
  • Colorized console output: Different colors for each log level
See the Logging documentation for detailed usage examples.

Observability tracing

Learn about distributed tracing with OpenTelemetry

Core package utils

Utilities in the shared core package

Authentication middleware

Middleware using network utilities

Error handling

How errors are handled in the Hono app

Build docs developers (and LLMs) love