Skip to content

Silvery vs Ink

External project claims last verified: 2026-04. Ink version: 7.0.0.

Ink (2017) brought React to the terminal. ~1.3M npm weekly downloads, used by Gatsby, Prisma, Terraform CDK, Shopify CLI, Claude Code, and many more. Mature, stable, and actively maintained — v7.0.0 shipped April 2026 with Kitty keyboard, useBoxMetrics, synchronized output, and more. Ink defined the category.

Silvery is a ground-up reimplementation with a different rendering architecture. Same Box, Text, useInput API — 99% of Ink's tests pass on silvery's compat layer.

Silvery grew out of building a complex terminal app where components needed to know their size during render, updates needed to be fast, and scroll containers, mouse events, focus scopes, and Playwright-style testing needed to just work. Three principles emerged: take the best from the web, stay true to the terminal, and raise the bar for developer ergonomics, architecture composability, and performance. The feature matrix below is what those principles look like in practice.

Highlights

The biggest differences at a glance:

  • Layout-first rendering — components know their size during render via useBoxRect(), not after. Ink's useBoxMetrics() returns 0×0 on first render.
  • Cell-level ANSI compositing — proper style stacking and color blending. Ink concatenates strings.
  • Incremental rendering in inline mode — only changed cells emit; native scrollback preserved. Ink does a full redraw every frame by default (has an incrementalRendering option for line-level diff).
  • Blurred inline/fullscreen boundaryinline mode gets fullscreen-level performance (cell-level incremental, no flicker, dynamic scrollback graduation). Fullscreen mode gets inline-level UX (app-managed scrollback, history access). Ink has a hard split between the two.
  • 3–27× faster (typically 15–20×) in mounted rerender benchmarks — cell-level dirty tracking with detailed benchmarks below. Bundle parity with Ink+Yoga.
  • Native scroll containersoverflow="scroll" + position="sticky". Ink's core has visible/hidden only (#222, open since 2019).
  • Mouse, drag, selection, find, clipboardSGR mouse protocol, onClick/onWheel, text selection, Ctrl+F search, OSC 52 clipboard. Ink has none of these.
  • 45+ built-in components — vs Ink's 6 core + @inkjs/ui's 13.
  • Multi-backend test matrixTermless runs tests across 10+ real terminal parsers (xterm.js, vt100, Ghostty, Kitty, Alacritty, ...). Ink has no equivalent.
  • Pure TypeScript, no WASM — synchronous import, normal GC, zero native dependencies.

Where Ink is stronger:

  • Community — ~1.3M npm weekly downloads, 50+ third-party packages, used in production since 2017. Silvery is newer and has a smaller community.
  • AccessibilityInk has aria-role, aria-label, aria-state, and useIsScreenReaderEnabled. Silvery has basic support.
  • DocumentationInk's README and community examples are extensive. Silvery's docs site is growing.

What's the same: React 19, Box/Text/useInput, flexbox layout, Static, useFocus, usePaste, useAnimation, useWindowSize, Kitty keyboard, synchronized output (DEC 2026), alternate screen, concurrent mode, Suspense. Most Ink code works with an import change.

Feature Matrix

Ink first, Silvery second. Features marked "core" are built into the framework; "ecosystem" means available via official or third-party packages.

Rendering

FeatureInk 7.0Silvery
ANSI compositingString concatenation; no compositing layerCell-level buffer with style stacking + color blending
Incremental rendering (fullscreen)Line-level diff; any change rewrites entire lineCell-level dirty tracking (7 flags/node), cell-level buffer diff
Incremental rendering (inline mode)Full redraw every frame by default (incrementalRendering option for line-level diff)Cell-level diff works in inline mode with native scrollback
Responsive layoutuseBoxMetrics() — post-layout via useEffect, returns 0×0 firstuseBoxRect() — dimensions available during render, first pass
Scrollable containersvisible/hidden only; ecosystem packages available (#222)overflow="scroll" + scrollTo — core framework, handles clipping
Sticky headersNoneposition="sticky" in scroll containers
Dynamic scrollbackAll items stay in render treeItems automatically graduate to terminal history; Cmd+F works
Fullscreen-like inlineHard split: inline = full redraw, fullscreen = no scrollbackInline mode with cell-level incremental rendering + scrollback graduation — fullscreen performance, inline UX
Inline-like fullscreenNoneAlt-screen with app-managed scrollback graduation — fullscreen control, inline history access
Render targetsTerminal onlyTerminal, Canvas 2D, DOM (experimental)

Performance & Size

MetricInk 7.0Silvery
Speed (mounted rerender)Baseline3–27× faster (typically 15–20×) in our benchmarks (details below)
Output efficiencyLine-level diff per change10–20× less output — cell-level diff + relative cursor addressing
Bundle size (gzipped)116.6 KB (Ink + Yoga WASM)114.9 KB (runtime + Flexily) — parity
Layout engineYoga WASM only (~45 KB, async init)Flexily (pure JS, ~2 KB, sync) or Yoga — pluggable
Layout cachingFull tree recomputation every passFingerprint + cache unchanged subtrees
Memory (long sessions)Yoga WASM linear heap can growNormal JS GC; graduated scrollback frees React tree
Native dependenciesYoga WASM binary blobNone — pure TypeScript
InitializationAsync WASM loadingSynchronous import

Interaction

FeatureInk 7.0Silvery
Mouse + drag-and-dropNoneSGR mouse, onClick/onWheel, hit testing, drag
Input layeringFlat: all handlers see all inputDOM-style bubbling, modal isolation, stopPropagation
Focus systemTab-order (useFocus, useFocusManager)Tree-based: scopes, spatial nav (arrow keys), click-to-focus, useFocusWithin
Text selection + find + copy-modeNoneMouse drag, Ctrl+F search, Esc,v keyboard selection
TextInput / TextAreaEcosystem: @inkjs/ui TextInput, ink-text-inputCore: built-in readline, cursor, selection, undo/redo
Command + keybinding systemNoneNamed commands, context-aware keys, parseHotkey("⌘K")
ClipboardNoneOSC 52 — works across SSH
Image renderingEcosystem (no maintained packages)Core: <Image> — Kitty graphics + Sixel + text fallback
HyperlinksOSC 8 (v6.8.0+)<Link>OSC 8 clickable URLs

Components & Framework

FeatureInk 7.0Silvery
Built-in components6 core (Box, Text, Static, Newline, Spacer, Transform)45+ core (VirtualList, Table, CommandPalette, TreeView, Toast, Tabs, SplitView, ...)
Official component library@inkjs/ui: 13 input-focused components (TextInput, Select, MultiSelect, Spinner, ProgressBar, ConfirmInput, EmailInput, PasswordInput, Badge, Alert, StatusMessage, lists)45+ components built into core — includes advanced widgets (Table, TreeView, CommandPalette, Toast, SplitView, ModalDialog, Tabs, TextArea, VirtualList)
Third-party ecosystem50+ community packages (ecosystem list)Newer, smaller community
Theme systemManual chalk styling84 color schemes, semantic tokens ($primary, $muted), auto-detect
Accessibilityaria-role, aria-label, aria-state, useIsScreenReaderEnabledBasic support
TEA state machinesNone@silvery/create: (action, state) → [state, effects], replay, undo
Plugin compositionNonewithCommands / withKeybindings / withDomEvents / withFocus
AnimationuseAnimation (frame/time/delta, v7.0+)useAnimation + easing functions + useAnimatedTransition
Resource cleanupManual unmount()using / Disposable — automatic teardown

Testing

FeatureInk 7.0Silvery
Test libraryink-testing-library (official)Built-in @silvery/test with Playwright-style locators, press(), buffer assertions
Headless renderingNone (always renders to stdout)createTerm({ cols, rows }) — no terminal needed
Terminal emulator in testsNonecreateTermless() via Termless — in-process terminal emulation with 10+ backends: xterm.js, vt100, libvterm, Ghostty, Kitty, Alacritty, WezTerm, and more. Matrix-test across real parsers.
Render invariant checksNoneSILVERY_STRICT=1 verifies incremental = fresh on every frame
Multi-backend verificationNoneSTRICT checks against vt100, xterm.js, and Ghostty backends
Visual snapshots + recordingsNonebufferToHTML(), Playwright capture, and Termless .tape recordings → animated GIF, PNG, SVG with 77 themes and window chrome

API & DX

FeatureInk 7.0Silvery
Simple APIrender(<App />)render(<App />) — same. run(<App />) adds runtime. pipe() for advanced composition
React DevToolsSupportedSILVERY_DEV=1 inspector (tree visualization, dirty flags, focus path)
Unicode utilitiesThird-party (string-width, slice-ansi, etc.)Built-in: 28+ functions for grapheme splitting, display width, CJK, ANSI-aware truncation
Console capturepatchConsole() (intercept-only)Built-in <Console /> component (composable, embeddable)
Non-TTY detectionTerminal size for piped processes (v6.7.0)isTTY(), resolveNonTTYMode(), renderString() fallback
Community~1.3M npm weekly downloads, mature ecosystemNewer, smaller community
DocumentationExtensive README, many community examplesGrowing docs site (silvery.dev)

Both have

React 19, Box/Text, flexbox, useInput, useApp/exit, Static, Transform, border styles, measureElement, Kitty keyboard, renderToString, useCursor, usePaste, useAnimation, useWindowSize, DEC mode 2026 (synchronized output), useFocus/useFocusManager, alternate screen, concurrent mode, Suspense.

Performance

Reproduce: bun run bench

Silvery is 3–27× faster (typically 15–20×) than Ink 7.0 in our mounted rerender benchmarks — synchronous rerender throughput where both frameworks keep a mounted app and call rerender().

Mounted rerender throughput

The 15–20× advantage comes from Silvery's pipeline making full use of React.memo — when components bail out, Silvery's dirty-tracking pipeline skips those nodes entirely (no buffer writes, no text processing). Ink re-renders and re-diffs the full tree regardless of memo bail-outs.

ScenarioSilvery advantage
Mounted cursor 100-item5.2×
Mounted cursor 200×606.5×
Mounted kanban 5×207.6×
Memo'd cursor 100 (inverse)15.8×
Memo'd cursor 1000 (inverse)19.1×
Memo'd kanban 5×2017.0×
Memo'd kanban 5×5026.7×

Output efficiency

Silvery emits 10–20× less output (much more for large trees) to the terminal than Ink's line-level diff on incremental updates. Cell-level buffer diff + relative cursor addressing.

Bundle size

PackageMinified + Gzippedvs Ink+Yoga
Ink 7.0 + Yoga WASM (baseline)116.6 KB1.00×
silvery/runtime (core + flexily)114.9 KB0.99× (tied)
silvery/ink (Ink compat layer)119.2 KB1.02×

Methodology

  • Tooling: vitest bench with warmup + automatic iteration count
  • Ink config: debug: true (synchronous rendering — both frameworks render every frame). debug: false uses Ink's throttle which batches frames, making the comparison unfair
  • Silvery: @silvery/test createRenderer uses the same production render core — headless, no test-only code paths
  • I/O: Both use mocked stdout — no real terminal I/O is measured
  • STRICT mode disabled (SILVERY_STRICT=0)
  • Fair comparison: Mounted scenarios keep both frameworks' React trees mounted and call rerender() with identical prop changes
  • Runtime: Bun (both frameworks). Node.js results pending — expected to show similar ratios
  • Reproduce: bun run bench

Compatibility

Silvery passes 918 of Ink 7.0's 931 tests (~98.6%). Chalk: 32/32 (100%). Run bun run compat to verify.

What we chose to do differently

The 13 remaining test failures are intentional design choices, not bugs:

  • W3C flexbox spec over Yoga quirks (4 tests) — Flexily follows the W3C flexbox specification for flex-wrap and aspect-ratio behavior. Yoga has non-standard behaviors here that Ink tests expect. We chose spec compliance. If you need exact Yoga parity, silvery supports Yoga as a pluggable engine.
  • TypeScript source over compiled build artifacts (2 tests) — Ink expects a ./build/ directory. Silvery ships raw TypeScript source (for Bun) + pre-built dist/ (for Node). The tests check for file paths that don't exist in silvery's layout.
  • Minor rendering edge cases (~7 tests) — SGR attribute ordering (dim+bold emission order differs), measureElement timing in synchronous render, and renderToString effect ordering. These produce identical visual output in practice.
Remaining failures breakdown
CategoryFailuresWhy
Flexily W3C spec divergence4flex-wrap (2), aspect ratio (2) — Flexily follows W3C, Yoga doesn't
Build artifact checks2Ink expects ./build/; silvery ships TypeScript + dist/
Minor rendering edge cases~7SGR order (2), measure timing (1), render-to-string timing (1), misc
Recently shipped compat (2026-04-09)
  • BackgroundContext shim (+27 tests)
  • maxFps render throttling (+3)
  • Kitty protocol negotiation bytes (+3)
  • Debug-mode cursor API (+3)
  • wrap="hard" (+1), CJK overlay (+2), overflow clipping (+3), per-side borderBackgroundColor (+5)

All Ink 7.0 hooks have full shims. Full API mapping →

If you need exact Yoga layout parity, Silvery supports Yoga as a pluggable engine.

Key Differences Explained

Responsive Layout

The core architectural difference — think CSS container queries for terminals. On the web, container queries were the #1 requested feature for a decade because the alternatives (media queries + ResizeObserver) meant rendering first, measuring after, then re-rendering with correct values. Terminal UIs hit the same wall.

Ink renders components, then runs Yoga layout. useBoxMetrics() provides dimensions after layout via useEffect, meaning the first render always sees {width: 0, height: 0}. With nested responsive components (board → column → card), each level needs its own measure→rerender cycle — N nesting levels, N visible flickers. Silvery runs layout first, then renders all components with actual dimensions via useBoxRect() in one batch.

tsx
// Ink: useBoxMetrics returns 0x0 on first render, updates via effect
function Card() {
  const ref = useRef(null)
  const { width, hasMeasured } = useBoxMetrics(ref)
  if (!hasMeasured)
    return (
      <Box ref={ref}>
        <Text>Loading...</Text>
      </Box>
    )
  return (
    <Box ref={ref}>
      <Text>{truncate(title, width)}</Text>
    </Box>
  )
}

// Silvery: useBoxRect returns actual dimensions immediately
function Card() {
  const { width } = useBoxRect()
  return <Text>{truncate(title, width)}</Text>
}

This difference cascades into scrolling, auto-truncation, responsive layouts, and any feature that needs to know "how much space do I have?" during the render pass rather than after it.

Scrolling

Ink's overflow property supports visible and hidden -- not scroll. Scrolling remains the #1 feature request (#222, open since 2019):

tsx
// Ink: manual virtualization with height estimation
<VirtualList
  items={items}
  height={availableHeight}
  estimateHeight={(item) => calculateHeight(item, width)}
  renderItem={(item) => <Card item={item} />}
/>

// Silvery: render everything, let the framework handle it
<Box overflow="scroll" scrollTo={selectedIdx}>
  {items.map(item => <Card key={item.id} item={item} />)}
</Box>

Input Layering

Ink's useInput is flat -- all registered handlers receive all input. Opening a modal dialog means manually checking flags in every handler:

tsx
// Ink: every handler must check modal state
useInput((input, key) => {
  if (isDialogOpen) return  // must guard in EVERY handler
  if (input === 'j') moveDown()
})

// Silvery: input layers isolate automatically
<InputLayerProvider>
  <Board />        {/* receives input when dialog is closed */}
  {isOpen && <Dialog />}  {/* consumes input, board never sees it */}
</InputLayerProvider>

Focus System

Ink provides tab-order focus with useFocus() — components register in a flat list and cycle via Tab/Shift+Tab. Silvery provides tree-based focus with scopes, spatial navigation (arrow keys move focus directionally based on layout position), click-to-focus, useFocusWithin, and DOM-style focus/blur events:

tsx
// Silvery: spatial focus navigation
<FocusScope>
  <Row>
    <FocusableCard /> {/* Left arrow → previous, Right arrow → next */}
    <FocusableCard />
    <FocusableCard />
  </Row>
</FocusScope>

Compat bridge: withInkFocus() provides Ink's flat-list focus system as a thin plugin. Apps using Ink's useFocus() / useFocusManager() work unchanged. For new code, silvery's useFocusable() is more capable — spatial awareness, focus scopes, event dispatch. See Compat Layer Architecture.

Mouse Support

Silvery implements SGR mouse protocol (mode 1006) with DOM-style event handling:

tsx
// Silvery: DOM-style mouse events
<Box
  onClick={(e) => selectItem(e.target)}
  onMouseDown={(e) => startDrag(e)}
  onWheel={(e) => scroll(e.deltaY)}
>
  <Text>Click me</Text>
</Box>

Ink has no mouse support.

Layout Engines

Silvery supports pluggable layout engines with the same flexbox API:

Flexily (default)Yoga (WASM)
Size (gzip)19 KB53 KB
LanguagePure JSC++ -> WASM
InitializationSynchronousAsync
100-node layout85 us88 us
50-node kanban57 us54 us
RTL directionSupportedSupported
Baseline alignmentNot supportedSupported

Both are fast enough for 60fps terminal UIs. Flexily is ~3x smaller with comparable performance. See the Flexily docs for details.

Flexily vs Yoga Philosophy

Flexily intentionally follows the W3C CSS Flexbox specification where Yoga diverges from it. These aren't bugs — they're design choices that make Flexily behave like browsers do:

BehaviorFlexily (CSS spec)Yoga (Ink)Why it matters
Default flexDirectionrowcolumnCSS §9.1: initial value is row. Ink chose column for document-flow convenience, but it surprises anyone coming from web CSS.
overflow:hidden + flexShrink:0Item shrinks to fit parentItem expands to content sizeCSS §4.5: overflow containers have min-size: auto = 0. Without this, an overflow:hidden child with 30 lines inside a height-10 parent computes as height 30 — defeating clipping.
alignContent distributionMatches browser behaviorSlightly different spacingMinor differences in how cross-axis space is distributed across flex lines.

If you prefer browser-standard flexbox, use Flexily (the default). If you need exact Ink layout parity, install Yoga and switch:

bash
bun add yoga-wasm-web
tsx
import { render } from "silvery"

await render(<App />, { layoutEngine: "yoga" })

Or set SILVERY_ENGINE=yoga to switch globally without code changes.

Most Ink apps use simple layouts (flexDirection="column", padding, borders) that work identically in both engines. The differences surface with advanced flexbox features like flexWrap, alignContent, and percentage-based flexBasis.

Terminal Protocol Coverage

Silvery implements a comprehensive set of terminal protocols. This matters for cross-terminal compatibility, modern features (images, clipboard, extended keyboard), and correct rendering in multiplexers like tmux and Zellij.

Escape Sequences

CategoryProtocolSilveryInk
SGR Styling16/256/Truecolor, bold, italic, dim, underline, strikethrough, inverseFullFull
Extended UnderlinesISO 8613-6: single, double, curly, dotted, dashed + underline color (SGR 58/59)FullNone
Cursor ControlCUP, CUU/D/F/B, EL, ED, DECSCUSR (block/underline/bar cursors)FullPartial
Scroll RegionsDECSTBM (set/reset), SU/SD (scroll up/down)FullNone

DEC Private Modes

ModeWhatSilveryInk
25 (DECTCEM)Cursor visibilityYesYes
1000 (X10)Basic mouse trackingYesNo
1002Button event tracking (press + drag)YesNo
1004Focus in/out reportingYesNo
1006 (SGR)Extended mouse protocol (large coordinates)YesNo
1049Alternate screen bufferYesYes
2004Bracketed paste modeYesYes (v7.0.0)
2026Synchronized output (flicker-free)YesYes (v7.0.0)
DECRPMMode query (CSI ? mode $ p)YesNo

OSC Sequences

OSCWhatSilveryInk
0/2Window titleYesNo
4Palette color query/setYesNo
7Directory reporting (shell integration)YesNo
8Hyperlinks (clickable URLs)YesNo
9iTerm2 notificationsYesNo
22Mouse cursor shape (pointer, text, crosshair, etc.)YesNo
52Clipboard access (copy/paste over SSH)YesNo
66Text sizing protocol (Kitty v0.40+, Ghostty)YesNo
99Kitty notificationsYesNo
133Semantic prompt markers (shell integration)YesNo

Keyboard & Input

ProtocolWhatSilveryInk
Kitty keyboardAll 5 flags (disambiguate, events, alternate, all keys, text)FullFull (v7.0.0)
Modifier detectionShift, Alt, Ctrl, Super/Cmd, Hyper, CapsLock, NumLockFullBasic
Key event typesPress, repeat, releaseFullPress only
Bracketed pasteusePaste hook with auto-enableFullusePaste hook (v7.0.0)
Focus reportingFocus in/out eventsFullNone

Graphics

ProtocolWhatSilveryInk
Kitty graphicsPNG transmission with chunking, ID-based managementFullNone
SixelRGBA-to-Sixel encoder with color quantizationFullNone
Auto-detectTry Kitty, fall back to Sixel, fall back to text placeholderYesN/A

Terminal Queries

QueryWhatSilveryInk
CPR (DSR 6)Cursor positionYesNo
CSI 14tPixel dimensionsYesNo
CSI 18tText area size (rows/cols)YesNo
DA1/DA2/DA3Device attributesYesNo
XTVERSIONTerminal identificationYesNo

Silvery uses these queries at startup for capability detection — automatically enabling Kitty keyboard, SGR mouse, synchronized output, and other features based on what the terminal supports.

When to Choose What

Both are good tools. The right choice depends on what you're building.

Choose Ink when:

  • Simpler CLIs and prompts: One-shot interactions, confirmation dialogs, progress indicators, setup wizards -- Ink handles these well with minimal setup
  • Ecosystem matters: Ink has ~1.3M weekly downloads, 50+ community components, and widespread adoption. If you need ink-select-input, ink-table, or other community packages, Ink's ecosystem is larger
  • Battle-tested stability: Ink has been in production across thousands of CLIs since 2017. It's a known quantity with well-understood behavior
  • Team familiarity: If your team already knows Ink, the context switch cost may not be worth it for a simple app
  • You don't need layout-aware rendering: If your components don't need to adapt to their available space, Ink's simpler pipeline is a fine fit

Choose Silvery when:

  • Complex interactive TUIs: Kanban boards, text editors, multi-pane dashboards -- apps where components need to know their dimensions during render
  • Scrollable containers: overflow="scroll" with native measurement, rather than manual virtualization
  • Mouse support and spatial focus: Click-to-focus, arrow-key navigation between components, drag support
  • Command system: Named commands with keybindings, help text, and runtime introspection
  • Interactive update performance: Per-node dirty tracking for sub-millisecond updates in large trees
  • Built-in component library: 45+ components without assembling third-party packages
  • Multi-target rendering: Terminal today, Canvas 2D and DOM in the future

Real-World Scenarios

Dashboard with Resizable Panes

Components need to know their dimensions to render content appropriately (charts, tables, wrapped text).

  • Ink: Use useBoxMetrics (post-layout, starts at 0x0). Re-render entire tree on resize.
  • Silvery: Each pane reads useBoxRect() and adapts immediately. Resize triggers layout-only pass (21 us for 1000 nodes).

Scrollable Task List

A list of 500+ items where the user navigates with j/k.

  • Ink: Requires manual virtualization with height estimation. overflow only supports visible/hidden.
  • Silvery: overflow="scroll" handles everything. VirtualList component optimizes large lists.

Kanban Board

3+ columns of cards, each column independently scrollable, cards showing truncated content.

  • Ink: Manual scroll per column, manual truncation, width-threading through props.
  • Silvery: Columns and cards auto-size. Each column scrolls independently. Text auto-truncates.

Search with Live Filtering

Type-ahead search with debounced results rendering.

  • Ink: useInput for text capture, manual list rendering. No input isolation between search box and results.
  • Silvery: InputLayerProvider for text input isolation, useBoxRect for result count fitting, useDeferredValue for responsive filtering.

Simple CLI Prompt

One-shot question, answer, exit.

  • Ink: Excellent -- large ecosystem of prompt components (ink-select-input, ink-text-input, ink-spinner).
  • Silvery: Built-in TextInput, SelectList, Spinner components. Works, but the community ecosystem is smaller.

Compatibility Coverage

Tested scenarios derived from common Ink issues:

ScenarioSilvery TestInk Issue
CJK character rendering (Chinese, Japanese, Korean)ime.test.tsx#759
Double-width character alignmentime.test.tsx, wide-char-truncate.test.ts#759
Emoji ZWJ sequencesime.test.tsx--
ANSI-aware text truncationtext-truncate-width.test.ts#584
Rapid keystrokes (burst input)input.test.tsxPR #782
borderDimColorborder-dim-color.test.tsx#840
Large component counts (1000+)performance.test.tsx, memory.test.tsx#694
Home/End key supportkeys.test.tsPR #829
Process exit timingexit.test.tsx#796
tmux renderingterminal-multiplexers.test.ts, sync-update.test.tsPR #846
Zellij renderingterminal-multiplexers.test.tsPR #846