---
title: "Winston"
description: "Why Blyp is a better fit than Winston for modern TypeScript apps, plus AI-assisted and manual migration steps."
canonical_url: "https://www.blyp.dev/docs/migrations/winston"
markdown_url: "https://www.blyp.dev/docs/migrations/winston.md"
last_updated: "2018-10-20"
x_farming_labs_generated_preamble: true
agent:
  task: "Replace Winston logger, format, and transport pipelines with Blyp configuration and structured calls."
  outcome: "Existing severity, metadata, file, and remote delivery behavior is preserved through Blyp."
  appliesTo:
    package:
      - "winston"
      - "@blyp/core"
  prerequisites:
    - "Inventory custom formats"
    - "transports"
    - "default metadata"
    - "exception handlers"
    - "and request middleware."
  files:
    - "package.json"
    - "blyp.config.ts"
    - "src"
  commands:
    - "pnpm add @blyp/core"
  sideEffects:
    - "Formatting and transport pipelines are replaced by Blyp destinations and connectors."
  verification:
    - "Compare representative levels"
    - "metadata"
    - "exceptions"
    - "and remote outputs before removing Winston."
  rollback:
    - "Retain the Winston module and dependency until behavior parity is verified."
  failureModes:
    - symptom: "A custom transport has no direct equivalent."
      resolution: "Map it to a supported connector or keep a temporary compatibility boundary while implementing an explicit sink."
---

# Winston
URL: /docs/migrations/winston
LLM index: /llms.txt
Description: Why Blyp is a better fit than Winston for modern TypeScript apps, plus AI-assisted and manual migration steps.
Related: /docs/migrations, /docs/basic-usage, /docs/structured-logs, /docs/configuration

<!-- farming-labs:agent-contract:start -->
## Agent Contract

Task: Replace Winston logger, format, and transport pipelines with Blyp configuration and structured calls.
Outcome: Existing severity, metadata, file, and remote delivery behavior is preserved through Blyp.

### Applies To

- Package: `winston`, `@blyp/core`

### Prerequisites

- Inventory custom formats
- transports
- default metadata
- exception handlers
- and request middleware.

### Files

- `package.json`
- `blyp.config.ts`
- `src`

### Commands

- `pnpm add @blyp/core`

### Side Effects

- Formatting and transport pipelines are replaced by Blyp destinations and connectors.

### Verification

- Compare representative levels
- metadata
- exceptions
- and remote outputs before removing Winston.

### Rollback

- Retain the Winston module and dependency until behavior parity is verified.

### Failure Modes

- A custom transport has no direct equivalent. — Recovery: Map it to a supported connector or keep a temporary compatibility boundary while implementing an explicit sink.
<!-- farming-labs:agent-contract:end -->

# Winston -> Blyp

Inventory Winston formats, transports, default metadata, and exception handlers first. Replace the
shared logger boundary, map metadata to structured fields and transports to Blyp destinations or
connectors, then compare output before uninstalling Winston. Keep a temporary boundary for custom
transports that lack a direct connector.

If your current setup centers on `winston.createLogger(...)`, custom transports, and formatter pipelines, Blyp gives you a simpler model: structured logs by default, first-party request logging for frameworks, built-in file logging and rotation, and connector delivery without transport object sprawl.

## Why Blyp can be better than Winston

- Winston is flexible, but that flexibility usually turns into formatter chains, transport setup, and app-specific conventions that teams have to maintain themselves.
- Blyp starts from structured logging instead of string formatting, so logs stay useful in local development and in production ingestion systems.
- Blyp includes framework-aware request logging, so HTTP logging is part of the main model instead of something you assemble around child loggers and middleware.
- Blyp keeps file logging, NDJSON output, rotation, and connector delivery under one config model.
- Blyp also extends beyond the classic server logger role with browser, Expo, database, and framework integration support.

If you already feel friction from custom Winston formats, multiple transports, or inconsistent request logging, that is usually the signal that the migration is worth it.

## Install

Install `@blyp/core` with your package manager:

```bash
# Bun (recommended)
bun add @blyp/core

# npm
npm install @blyp/core

# pnpm
pnpm add @blyp/core

# yarn
yarn add @blyp/core
```

## Let AI do the migration first

Before doing this by hand, give your AI workflow the Blyp migration references:

- [Winston migration reference](https://github.com/Blyphq/skills/blob/main/migration/references/migrate-winston.md)
- [Transport mapping reference](https://github.com/Blyphq/skills/blob/main/migration/references/transport-mapping.md)
- [Migration references directory](https://github.com/Blyphq/skills/tree/main/migration/references)

That gives the model the Winston-to-Blyp mapping up front, which is useful for bulk replacements across a large codebase. After that, use the manual guide below to review the resulting structure and the behavior changes.

## Most common replacement

**Winston**

```ts
import winston from "winston";

const logger = winston.createLogger({
  level: "info",
  transports: [
    new winston.transports.File({ filename: "logs/app.log" }),
  ],
});
```

**Blyp**

```ts
import { createStandaloneLogger } from "@blyp/core";

const logger = createStandaloneLogger({
  level: "info",
  destination: "file",
});
```

If you just want the shared root logger, use the named export:

```ts
import { logger } from "@blyp/core";
```

## API equivalents

| Winston | Blyp equivalent |
| --- | --- |
| `winston.createLogger({ level: "info" })` | `logger` or `createStandaloneLogger({ level: "info" })` |
| `winston.transports.File` | `destination: "file"` with optional `file.rotation` config |
| `winston.transports.Http` | connector config under `connectors`, such as Better Stack, Sentry, PostHog, or OTLP |
| `logger.child({ requestId })` | `logger.child({ requestId })` for stable bindings, or a framework adapter request logger for request-scoped logging |
| `format.combine(...)`, `format.json()`, custom formatters | structured fields on each log call, or batched payloads with `createStructuredLog()` |

For example, a Winston formatter pipeline often becomes structured fields instead of string rewriting:

```ts
import { createStructuredLog, logger } from "@blyp/core";

logger.info("user login", {
  userId: "usr_123",
  tenantId: "tenant_456",
});

const structuredLog = createStructuredLog("checkout", {
  requestId: "req_123",
});

structuredLog.set({
  user: { id: "usr_123" },
  payment: { provider: "stripe", status: "authorized" },
});

structuredLog.emit({
  level: "info",
  message: "checkout completed",
  status: 200,
});
```

## Behavioral differences

- Blyp is structured-first; there is no formatter pipeline equivalent to Winston `format.combine(...)`.
- Transports are configured through logger or config state, not instantiated transport objects.
- File logging is the default destination model in Blyp.
- `createStructuredLog()` accumulates fields and emits only on `.emit()`.
- Blyp exposes named loggers and structured metadata rather than string-rewriting format hooks.

For request logging, Winston child loggers are not the main migration target. Use the appropriate framework adapter, such as `createLogger()` from `@blyp/core/express` or `@blyp/core/fastify`, when the old app created request-local loggers in middleware.

## Related docs

- [Basic Usage](/docs/basic-usage)
- [Structured Logs](/docs/structured-logs)
- [Configuration](/docs/configuration)
- [File Logging](/docs/file-logging)
- [Connectors](/docs/connectors)
- [Integrations](/docs/integrations)

## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
Docs-scoped sitemap: [/docs/sitemap.md](/docs/sitemap.md).
Well-known sitemap: [/.well-known/sitemap.md](/.well-known/sitemap.md).
