> For AI agents: the complete documentation index is available at https://open-spaced-repetition.github.io/ts-fsrs/llms.txt, the full documentation bundle is available at https://open-spaced-repetition.github.io/ts-fsrs/llms-full.txt.

# Quick start

Migrating an existing application? Follow the [v5 → v6 and FSRS-7 migration guide](https://open-spaced-repetition.github.io/ts-fsrs/guide/migration.md).

## Installation

`ts-fsrs` requires Node.js 24 or later.


```sh [npm]
npm install ts-fsrs
```

```sh [yarn]
yarn add ts-fsrs
```

```sh [pnpm]
pnpm add ts-fsrs
```

```sh [bun]
bun add ts-fsrs
```

```sh [deno]
deno add npm:ts-fsrs
```

Install `@open-spaced-repetition/binding` separately only when you need to train FSRS parameters or convert review-log CSV files.

## Start with DefaultScheduler

`DefaultScheduler()` is the fastest way to add FSRS scheduling. It defaults to FSRS-7 and includes the standard retention, statistics, learning-step, maximum-interval, monotonic-interval, and scheduled-days policies; fuzzing is available as an option.

```ts twoslash file="../../snippets/run-code/default-scheduler.ts"
import { DefaultScheduler, Rating } from 'ts-fsrs'

const now = new Date('2026-01-01T00:00:00.000Z')
const scheduler = await DefaultScheduler({
  version: 'FSRS-7',
  desiredRetention: 0.9,
  enableShortTerm: true,
  learningSteps: ['1m', '10m'],
  relearningSteps: ['10m'],
  enableFuzz: false,
  maximumInterval: 36_500,
})
const card = scheduler.newCard({ cardId: 'quick-start', now })
const result = scheduler.review({ card, grade: Rating.Good, now })

console.log(
  JSON.stringify(
    {
      state: result.card.state,
      dueAt: result.card.dueAt,
      stability: result.card.stability,
      stabilityFast: result.card.stabilityFast,
      difficulty: result.card.difficulty,
      rating: result.revlog.rating,
    },
    null,
    2
  )
)

```


▶ Run code

The example makes the common defaults explicit. Change `desiredRetention`, learning and relearning steps, fuzzing, or `maximumInterval` for your product; omit `weights` to use the preset for the selected FSRS version.

## Create a scheduler

Use `defineScheduler` when you need to choose the model, chronology, or middleware yourself. It creates a reusable definition; calling `.create()` validates the configuration and returns an independent scheduler.

`chrono` defines how time is represented, stored on cards and review logs, and used in scheduling calculations, allowing you to use JavaScript `Date`, Temporal, or numeric time values. `chrono.normalize` uses a `ChronoTimeNormalizer` schema to convert card or revlog time fields into `{ previous, current }` for scheduling and rollback.

```ts twoslash file="../../snippets/run-code/define-scheduler.ts"
import { dateChrono, defineScheduler, Rating } from 'ts-fsrs'
import { FSRS7_DEFAULT_WEIGHTS, FSRS7Model } from 'ts-fsrs/models/fsrs-7'

// Reuse this definition as the program's scheduling preset.
const schedulerDefinition = defineScheduler({
  model: FSRS7Model,
  chrono: dateChrono,
})

// Create an independent scheduler when a user's config is available.
const scheduler = schedulerDefinition.create({
  config: {
    weights: FSRS7_DEFAULT_WEIGHTS,
    fractionalDays: true,
  },
})

const now = new Date('2026-01-01T00:00:00.000Z')
const card = scheduler.newCard({ now })
const result = scheduler.review({ card, grade: Rating.Good, now })

console.log(
  JSON.stringify(
    {
      state: result.card.state,
      dueAt: result.card.dueAt,
      stability: result.card.stability,
      difficulty: result.card.difficulty,
      stabilityFast: result.card.stabilityFast,
      rating: result.revlog.rating,
    },
    null,
    2
  )
)

```


▶ Run code

:::note Reuse the scheduler definition
Keep the result of `defineScheduler(...)`, including any middleware added with `.use(...)`, as a program-level preset. Call `schedulerDefinition.create({ config })` when a user or collection needs a scheduler; each call validates that configuration and returns an independent instance.
:::

Use the code block's copy button to copy the original source, or run it directly in the dedicated Worker. The fixed `now` value keeps the output reproducible.

- `newCard()` creates the scheduler's default card shape.
- `review()` returns a new card and revlog without mutating the input card.
- Add policy middleware with `.use(...)` to the reusable definition before creating user-specific schedulers.
