TanStack
Guides

Bundle Size and Performance

TanStack Charts is split around capability boundaries. A chart should pay for its marks and the specific analytical or spatial primitives it imports, not a universal chart catalog.

Import the narrow path

The package root is the ergonomic path for ordinary charts:

ts
import { defineChart, lineY } from '@tanstack/charts'

Capability subpaths make optional boundaries explicit:

ts
import { mountChart } from '@tanstack/charts/dom'
import { mountCanvasChart } from '@tanstack/charts/canvas'
import { mountChartRenderer } from '@tanstack/charts/renderer'
import { renderChartImage } from '@tanstack/charts/export'
import { focusX } from '@tanstack/charts/focus'
import { d3Curve } from '@tanstack/charts/d3/shape'

Canvas is opt-in. The default core and every default framework entry remain SVG-based. Canvas enters the module graph only through @tanstack/charts/canvas, @tanstack/react-charts/canvas, or @tanstack/octane-charts/canvas. The React and Octane /core entries accept an application-supplied renderer without importing Canvas.

Non-cartesian geometry is subpath-only:

ts
import { polar, radialArc } from '@tanstack/charts/polar'
import { geoShape } from '@tanstack/charts/geo'

The root entry does not re-export those capabilities. Polar brings in its d3-shape geometry only when the polar subpath is imported; geography does the same for d3-geo. Import pie, configured scales, projections, and curve factories from their granular D3 modules as the chart requires them. Political boundary data and topojson-client remain application dependencies; importing geoShape does not bundle an atlas.

Your bundler must honor ESM exports and tree shaking. Avoid namespace imports when a named or subpath import communicates the real dependency.

Import D3 by capability

TanStack Charts does not bundle a hidden analytical runtime. Import only the D3 modules that own the scale, shape, transform, or spatial behavior a chart needs. A basic bar chart can use d3-scale; a stacked area may add d3-shape; a large nearest-point interaction may add a spatial index.

The canonical dependency map and official references live in Scales and D3.

Measure the complete feature

Compare production bundles that render the same behavior:

  • the same chart family and curve;
  • the same number and kind of guides;
  • the same tooltip and keyboard behavior;
  • the same framework adapter;
  • the same data preparation;
  • the same export or spatial capability, when used.

Report raw, gzip, and Brotli sizes. Record the package manager lockfile, bundler, minifier, target, and entry source. A root package tarball size or an unminified source count is not a user bundle measurement.

The library comparison publishes the current pinned four-chart, three-tier bundle snapshot and its limits.

The repository's bundle gates use isolated entries so adding a complex mark cannot silently increase the smallest chart. Polar has separate arc-only and D3-pie consumer ceilings plus a complete scale-backed line/scatter ceiling; geography has its own projected-shape ceiling. The ordinary line, representative-mark, DOM, and framework entries remain exact byte locks.

Separate preparation, scene, and paint

Measure three layers independently:

  1. Data preparation: sorting, grouping, binning, stacking, or layout.
  2. Scene build: channels, scales, guides, marks, and focus points.
  3. Surface paint: SVG serialization and keyed reconciliation, or Canvas draw calls, plus optional animation.

This separation reveals whether an expensive chart needs a better encoding, a framework-memoized transform, fewer scene nodes, or a different renderer.

Choose a sane representation

The fastest way to render too much data is to avoid rendering it:

  • bin dense distributions;
  • aggregate repeated categories;
  • use an envelope or sampled line when individual points are not readable;
  • restrict a time chart to a controlled visible window;
  • use facets only when each panel remains interpretable;
  • virtualize application chrome and lanes when only a subset is visible.

Every visible SVG node carries DOM and paint cost. Canvas removes the per-element DOM cost, but not scene construction, draw work, interaction-point memory, or visual overplotting. More marks are justified only when they communicate more information.

See Large Data for representation thresholds and interaction policies.

Update efficiently

  • Keep definitions at module scope.
  • Reuse input references when data is unchanged.
  • Give every mutable visual entity a stable key.
  • Memoize expensive derived data in the application.
  • Bound streaming windows.
  • Build a spatial index only when a measurement justifies it.
  • Disable animation for high-frequency updates or reduced-motion users.

The host reconciles nodes by key and starts interrupted animation from the currently painted geometry. Stable identity helps both correctness and performance; it does not reduce the cost of an unnecessarily large scene.

Performance acceptance

For each supported feature, keep a reproducible gate for:

  • cold render time;
  • warm update and reorder time;
  • resize time;
  • node count;
  • interaction latency;
  • retained heap after repeated mount/update/destroy;
  • smallest relevant production bundle.

Compare at multiple data sizes and identify the first size where the representation itself stops being sensible. Performance claims should name the fixture and percentile, not imply one universal winner.

See Testing and Debugging for correctness gates that must accompany performance results.