# How Cycle (Sprint) Management and Burn-Down Charts Work in Plane

> Understand Plane's cycle sprint management and burn-down charts. Learn how Plane visualizes progress and actual velocity against ideal completion lines for efficient agile workflows.

- Repository: [Plane/plane](https://github.com/makeplane/plane)
- Tags: how-to-guide
- Published: 2026-06-18

---

**Plane manages agile sprints through a MobX-powered CycleStore that retrieves time-boxed iteration data, normalizes mixed-version progress formats into unified chart structures, and renders interactive burn-down or burn-up visualizations comparing actual velocity against ideal completion lines.**

Plane (makeplane/plane) implements cycle management as a core agile project management feature, enabling teams to track sprint progress through sophisticated burn-down analytics. The architecture separates data fetching, state normalization, and visualization concerns across dedicated services and utility layers. This design ensures real-time chart updates while supporting both issue-count and estimate-point based progress tracking.

## Cycle State Management and Data Structure

In Plane, a **cycle** represents a time-boxed sprint container backed by `ICycle` objects stored in the backend. The frontend centralizes all cycle state within the **CycleStore** ([`apps/web/core/store/cycle.store.ts`](https://github.com/makeplane/plane/blob/main/apps/web/core/store/cycle.store.ts)), a MobX store that maintains two critical data structures: `cycleMap` for entity storage and `fetchedMap` for tracking API request status. This caching strategy prevents redundant network calls and ensures instantaneous UI reactions when users switch between project views.

The store exposes specific fetch methods—`fetchWorkspaceCycles`, `fetchAllCycles`, and `fetchActiveCycle`—that orchestrate data retrieval through the **CycleService** ([`apps/web/core/services/cycle.service.ts`](https://github.com/makeplane/plane/blob/main/apps/web/core/services/cycle.service.ts)). These methods populate the store while managing loading states and error handling across the application.

## Normalizing Legacy and Modern Progress Formats

Plane's evolution introduced two distinct progress data schemas that the system normalizes for consistent chart rendering. **Version 1** cycles provide `distribution` or `estimate_distribution` objects mapping dates to completion counts, while **Version 2** cycles return a `progress` array containing daily total aggregates.

The utility function `formatActiveCycle` in [`packages/utils/src/cycle.ts`](https://github.com/makeplane/plane/blob/main/packages/utils/src/cycle.ts) handles this normalization, converting both schemas into a unified `TProgressChartData` structure. This function accepts configuration flags including `isBurnDown` (to determine whether `actual` represents pending or completed work) and `isTypeIssue` (to toggle between issue counts and estimate points). The normalization ensures that regardless of backend data age, the visualization components receive a consistent interface.

## Calculating Ideal Velocity Lines

Beyond raw data formatting, the system calculates theoretical sprint velocity through an `ideal` function implemented in [`packages/utils/src/cycle.ts`](https://github.com/makeplane/plane/blob/main/packages/utils/src/cycle.ts). This function computes the expected completion rate based on the total scope and the fraction of the sprint duration elapsed, generating a dotted reference line that appears alongside actual progress in charts.

For burn-down visualizations, the function returns `actual = pending` to show remaining work decreasing over time. For burn-up modes, it returns `actual = completed` to visualize accumulation toward scope completion. The **CycleStore** tracks user preferences for these display modes through `getPlotTypeByCycleId`, which defaults to `"burndown"` but supports toggling to `"burnup"` per cycle.

## Rendering Interactive Charts

The **ProgressChart** component ([`apps/web/core/components/core/sidebar/progress-chart.tsx`](https://github.com/makeplane/plane/blob/main/apps/web/core/components/core/sidebar/progress-chart.tsx)) consumes the normalized distribution data and renders the final visualization using an **AreaChart** from `@plane/propel` ([`packages/propel/src/charts/area-chart/root.tsx`](https://github.com/makeplane/plane/blob/main/packages/propel/src/charts/area-chart/root.tsx)). This component accepts a `distribution` object mapping dates to work units, a `totalIssues` count for scale reference, and a `plotTitle` for labeling.

The resulting visualization displays dates on the X-axis and work units on the Y-axis, plotting both the calculated ideal line and the current actual progress as filled areas. Users can switch between burn-down and burn-up perspectives without refetching data, as the store's `plotType` state triggers local recalculation through `formatActiveCycle`.

## Filtering and Numeric Progress Calculations

Plane supplements visual charts with numeric progress indicators used in status badges and summary tiles. The `calculateCycleProgress` function in [`packages/utils/src/cycle.ts`](https://github.com/makeplane/plane/blob/main/packages/utils/src/cycle.ts) computes completion percentages by comparing completed items against total scope, explicitly excluding cancelled issues from the calculation.

For list views, the `cycleFilter` store supplies criteria such as status and date ranges, while helper functions `orderCycles` and `shouldFilterCycle` (also in [`packages/utils/src/cycle.ts`](https://github.com/makeplane/plane/blob/main/packages/utils/src/cycle.ts)) apply these filters before rendering. This ensures that cycle management interfaces remain performant even when displaying large historical sprint datasets.

## Integrating Cycle Charts in Custom Components

Developers can embed sprint analytics into custom views by combining the CycleStore with normalization utilities. The following pattern demonstrates retrieving the active cycle and preparing burn-down data:

```tsx
import { observer } from "mobx-react-lite";
import { useRootStore } from "@/hooks/use-root-store";
import { formatActiveCycle } from "@plane/utils";
import ProgressChart from "@/components/core/sidebar/progress-chart";

const SprintBurnDown = observer(() => {
  const { cycleStore } = useRootStore();
  const activeCycle = cycleStore.currentProjectActiveCycle;

  if (!activeCycle) return <div>No active sprint</div>;

  const chartData = formatActiveCycle({
    cycle: activeCycle,
    isBurnDown: true,
    isTypeIssue: true,
  });

  const distribution = Object.fromEntries(
    chartData.map(d => [d.date, d.actual ?? 0])
  );

  return (
    <ProgressChart
      distribution={distribution}
      totalIssues={activeCycle.total_issues ?? 0}
      plotTitle="issues"
    />
  );
});

```

This implementation leverages the store's cached data to avoid API calls, uses `formatActiveCycle` to handle version compatibility, and delegates rendering to the shared `ProgressChart` component.

## Summary

- **CycleStore** ([`apps/web/core/store/cycle.store.ts`](https://github.com/makeplane/plane/blob/main/apps/web/core/store/cycle.store.ts)) centralizes sprint state using MobX, caching cycles in `cycleMap` and tracking fetch status in `fetchedMap` to optimize performance.
- **CycleService** ([`apps/web/core/services/cycle.service.ts`](https://github.com/makeplane/plane/blob/main/apps/web/core/services/cycle.service.ts)) provides the API layer for retrieving workspace and project cycles via methods like `fetchActiveCycle`.
- **Data normalization** occurs in [`packages/utils/src/cycle.ts`](https://github.com/makeplane/plane/blob/main/packages/utils/src/cycle.ts), where `formatActiveCycle` unifies Version 1 and Version 2 progress formats into `TProgressChartData`.
- **Ideal velocity calculation** uses the total scope and elapsed time fraction to generate reference lines for comparison against actual progress.
- **Visualization** relies on `ProgressChart` and the Propel `AreaChart` component to render interactive burn-down or burn-up views based on the store's `plotType` setting.
- **Progress metrics** such as completion percentages are calculated by `calculateCycleProgress`, excluding cancelled items for accurate sprint health indicators.

## Frequently Asked Questions

### How does Plane handle different progress data formats in older versus newer cycles?

Plane supports two backend schemas through the `formatActiveCycle` utility in [`packages/utils/src/cycle.ts`](https://github.com/makeplane/plane/blob/main/packages/utils/src/cycle.ts). Legacy cycles provide `distribution` objects while modern cycles use a `progress` array; the normalizer converts both into a consistent `TProgressChartData` structure that charts consume uniformly.

### What determines whether Plane displays a burn-down or burn-up chart?

The **CycleStore** maintains a per-cycle `plotType` state accessed via `getPlotTypeByCycleId`, defaulting to `"burndown"`. When users toggle views, the flag updates and `formatActiveCycle` adjusts its return values—returning `pending` counts for burn-down and `completed` counts for burn-up—without requiring additional API requests.

### How does Plane calculate the ideal line shown in sprint charts?

The `ideal` function in [`packages/utils/src/cycle.ts`](https://github.com/makeplane/plane/blob/main/packages/utils/src/cycle.ts) calculates the expected completion rate by dividing the total sprint scope by the time elapsed since the cycle start date. This generates a linear projection that appears as a dotted reference line alongside actual progress in the `AreaChart` visualization.

### Where does Plane store filter settings for cycle lists?

Filter criteria are managed by the `cycleFilter` store and applied through helper functions `orderCycles` and `shouldFilterCycle` located in [`packages/utils/src/cycle.ts`](https://github.com/makeplane/plane/blob/main/packages/utils/src/cycle.ts). These utilities process user-selected filters—such as status or date ranges—before cycles render in list views, ensuring consistent sorting and visibility across the application.