DEV Community

Shrijith Venkatramana
Shrijith Venkatramana

Posted on

How FSRS Replaces 30-Year-Old Algorithms in Modern Memory Software

Hello, I'm Shrijith Venkatramana. I'm building git-lrc, an AI code reviewer that runs on every commit. Star Us to help devs discover the project. Do give it a try and share your feedback for improving the product.


Why your spaced repetition app needs a scheduler that learns

Picture this: You are building a language learning app. Your users review flashcards daily. Some cards they remember easily. Others they forget repeatedly. Your scheduler must decide when to show each card again.

For decades, the industry standard was SM-2 — the algorithm behind SuperMemo and Anki. SM-2 uses a single number (an "ease factor") to adjust intervals. It works. But it does not learn from user behavior.

Then came Jarrett Ye. Working on MaiMemo, a language learning platform in China, Ye and his team asked a fundamental question: Can we build a scheduler that actually models how human memory works?

The result was FSRS — the Free Spaced Repetition Scheduler. It is now the default scheduler in Anki as of version 23.10. It is open source. And it is backed by serious research: two peer-reviewed papers, one at ACM SIGKDD 2022 and one in IEEE Transactions on Knowledge and Data Engineering.

This article explains FSRS from the ground up. We start with intuition. We go deeper into the math. We show code. By the end, you will know enough to implement FSRS in your own application.

1. The Problem with One-Number Scheduling

SM-2 uses a single parameter — the "ease factor" — to adjust intervals for all cards. If you rate a card "easy", the ease factor increases. If you rate it "hard", the ease factor decreases.

This works for simple cases. But memory is not simple.

Consider two cards you review today:

  • Card A: "Paris is the capital of France" — you know this well.
  • Card B: "The chemical symbol for Tungsten is W" — you always confuse this.

Both cards might have the same ease factor under SM-2. But they are not the same. One is easy. One is hard. One should have longer intervals. The other should have shorter intervals.

SM-2 cannot distinguish them. It uses one number for all cards.

FSRS solves this by using three numbers per card.

2. The DSR Model: Three Numbers Instead of One

FSRS models memory using three variables:

Difficulty (D) — How hard is this card? Range: 1.0 (easiest) to 10.0 (hardest). A card about "Paris" gets low difficulty. A card about "Tungsten" gets higher difficulty.

Stability (S) — How strong is the memory? Definition: the number of days for recall probability to drop from 100% to 90%. If S = 30 days, you have a 90% chance of recalling it after 30 days.

Retrievability (R) — The probability you will recall it right now. Range: 0 to 1. This changes daily as time passes.

Here is the key insight: Stability and Difficulty are properties of the card. Retrievability is a property of the card and the time since your last review.

When you review a card, FSRS updates D and S based on your rating. Between reviews, R decays over time.

The scheduler's job is simple: show the card when R drops to your target retention (usually 90%).

3. The Forgetting Curve: Why Power Beats Exponential

Most spaced repetition systems use an exponential forgetting curve:

R(t) = 0.9^(t/S)
Enter fullscreen mode Exit fullscreen mode

FSRS uses a power-law forgetting curve:

R(t, S) = (1 + F * (t/S))^(-0.5)
Enter fullscreen mode Exit fullscreen mode

Where F = 19/81 ~ 0.2346.

Why a power law? The research shows that a power function fits human memory data better than an exponential function.

Here is the intuition: Human memory is not a single process. It is a superposition of many memory traces with different decay rates. A power law emerges naturally when you average many exponential decays.

The practical difference: At long intervals, a power law predicts more forgetting than an exponential curve. This matches real data — we forget more over long periods than exponential models predict.

At short intervals (under 10 days), the two curves are nearly identical. The difference shows up over weeks and months.

For developers: this means FSRS gives longer intervals for well-known cards and shorter intervals for hard cards — with better accuracy than exponential models.

4. State Updates: The Math Behind Each Review

When a user rates a card, FSRS updates the memory state. Here is how it works.

Initial Review (New Card)

For a new card, FSRS sets initial stability based on the user's rating:

Rating Initial Stability
Again (1) 0.4 days
Hard (2) 0.6 days
Good (3) 2.4 days
Easy (4) 5.8 days

These values come from default parameters — trained on 738 million reviews from 20,000 users.

Initial difficulty is calculated as:

D_0(G) = w_4 - e^(w_5 * (G-1)) + 1
Enter fullscreen mode Exit fullscreen mode

Clamped to [1, 10]. Higher ratings yield lower difficulty.

Successful Review (Grade >= 2)

When you remember a card, difficulty updates first:

D_next = D_prev - w_6 * (G - 3)
D_new = w_7 * D_0(3) + (1 - w_7) * D_next
Enter fullscreen mode Exit fullscreen mode
  • Rating > 3 -> difficulty decreases (card gets easier)
  • Rating < 3 -> difficulty increases (card gets harder)
  • Mean reversion (w_7) prevents extreme values

Then stability updates:

GrowthFactor = e^(w_8) * (11 - D) * S^(-w_9) * (e^(w_10*(1-R)) - 1) * h * b
Enter fullscreen mode Exit fullscreen mode

Where:

  • h = w_15 if Grade = 2 (Hard penalty), else 1
  • b = w_16 if Grade = 4 (Easy bonus), else 1

The new stability is:

S_new = S_prev * (1 + GrowthFactor)
Enter fullscreen mode Exit fullscreen mode

This looks complex. But the intuition is simple: The growth factor depends on difficulty, current stability, retrievability at review time, and the user's rating.

  • Higher difficulty -> smaller growth (hard cards improve more slowly)
  • Higher current stability -> smaller growth (already stable cards improve more slowly)
  • Lower retrievability -> larger growth (if you almost forgot it, reviewing it strengthens memory more)
  • "Easy" rating -> bonus growth
  • "Hard" rating -> penalty

Failed Review (Grade = 1)

When you forget a card, stability decreases:

S_new = w_17 * D^(-w_18) * (S_prev + 1)^(-w_19)
Enter fullscreen mode Exit fullscreen mode

Difficulty increases:

D_new = D_prev + w_11
Enter fullscreen mode Exit fullscreen mode

Clamped to [1, 10].

5. Interval Calculation: When to Show the Card

Once we have stability S and target retention R_req, we calculate the interval:

I(S, R_req) = S * (81/19) * (R_req^(-2) - 1)
Enter fullscreen mode Exit fullscreen mode

For R_req = 0.9 (90% target):

I = S * (81/19) * (1/0.81 - 1) = S * (81/19) * (19/81) = S
Enter fullscreen mode Exit fullscreen mode

At 90% retention, the optimal interval equals stability.

For other retention targets:

  • R_req = 0.85 -> I ~ 0.75 * S (shorter interval, higher retention)
  • R_req = 0.95 -> I ~ 1.38 * S (longer interval, lower retention)

This trade-off is the core economics of spaced repetition: Higher retention means more reviews. Lower retention means fewer reviews but more forgetting.

6. The Optimizer: Learning from Your Data

The scheduler uses 19 parameters (w_0 through w_19). Default parameters come from 738 million reviews across 20,000 users.

But FSRS can do better: it can learn your personal memory patterns from your review history.

The optimizer uses two techniques:

  1. Maximum Likelihood Estimation (MLE) — Find parameters that make your observed review outcomes most probable
  2. Backpropagation Through Time (BPTT) — Train the model on time-series review data

The optimizer takes your review logs — each with timestamp, card ID, and rating — and finds the parameters that best fit your data.

In practice, optimized FSRS beats default FSRS, which beats SM-2:

  • Default FSRS better than SM-2 for 92% of users
  • Optimized FSRS better than SM-2 for 99% of users

For developers: The FSRS Optimizer is available as a Python library. You can feed it review logs and get optimized parameters. The optimizer runs on the client side (in the browser via WebAssembly) or on a server.

7. Implementation: Code Examples

Python

from fsrs import Scheduler, Card, Rating

# Initialize with default parameters
scheduler = Scheduler()

# Create a new card
card = Card()

# Simulate a review with "Good" (rating 3)
review_log = scheduler.review_card(card, Rating.Good)

# Get the next review date
next_interval_days = review_log.scheduled_days

print(f"Review again in {next_interval_days} days")
Enter fullscreen mode Exit fullscreen mode

Py-FSRS is available on PyPI.

TypeScript

import { createEmptyCard, fsrs, Rating } from 'ts-fsrs';

const card = createEmptyCard();
const scheduler = fsrs();

const { card: updatedCard, reviewLog } = scheduler.review(card, Rating.Good);

console.log(`Review again in ${updatedCard.due} days`);
Enter fullscreen mode Exit fullscreen mode

ts-fsrs is available on npm.

Rust

use fsrs::{FSRS, Card, Rating};

let mut fsrs = FSRS::default();
let mut card = Card::default();

let (new_card, log) = fsrs.review(card, Rating::Good)?;

println!("Review again in {} days", new_card.due);
Enter fullscreen mode Exit fullscreen mode

FSRS-rs provides a Rust implementation with full training support.

Optimizing Parameters

from fsrs_optimizer import optimize_parameters
from fsrs import FSRSItem

# Load your review logs
items = load_review_logs()  # List of FSRSItem

# Optimize parameters for your data
optimized_params = optimize_parameters(items)

# Use optimized parameters
scheduler = FSRS(parameters=optimized_params)
Enter fullscreen mode Exit fullscreen mode

The FSRS Optimizer package handles this workflow.

9. Developer Considerations

Data Requirements

FSRS works from day one with default parameters. But optimization requires data:

  • At least 100 reviews for basic optimization
  • 1,000+ reviews for reliable personalization

Implementation Options

FSRS has implementations in:

  • Python (py-fsrs)
  • TypeScript (ts-fsrs)
  • Rust (fsrs-rs)
  • Dart
  • PHP
  • C# (.NET)

Migration from SM-2

If you have existing users with SM-2 data, you can migrate. FSRS can estimate initial D and S from review history. Anki handles this automatically when you enable FSRS.

Free Scheduling

The "Free" in FSRS means you can review cards early or late. FSRS adapts. If you review a card late and still remember it, stability increases more than if you reviewed it on time. If you review early, the algorithm accounts for that too.

10. Conclusion

FSRS represents a fundamental improvement over traditional spaced repetition algorithms. It models memory with three variables instead of one. It uses a power-law forgetting curve that fits human memory data better. It learns from each user's review history.

The research is solid: two peer-reviewed papers, one at ACM SIGKDD 2022 and one in IEEE TKDE 2023. The data is massive: 738 million reviews from 20,000 users. The results are clear: FSRS beats SM-2 for 92% of users with default parameters, and for 99% with optimized parameters.

For developers, FSRS is ready to use. Pick an implementation. Import the library. Replace your scheduler. Your users will spend less time reviewing and remember more.

Now your turn: Have you implemented a spaced repetition system? What algorithm did you use? Share your experience in the comments — including the data size, the user base, and what you learned.


*AI agents write code fast. They also silently remove logic, change behavior, and introduce bugs -- without telling you. You often find out in production.

git-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.*

Any feedback or contributors are welcome! It's online, source-available, and ready for anyone to use.

GitHub logo HexmosTech / git-lrc

Free, Micro AI Code Reviews That Run on Git Commit




GenAI today is a race car without brakes. It accelerates fast -- you describe something, and large blocks of code appear instantly. But AI agents silently break things: they remove logic, relax constraints, introduce expensive cloud calls, leak credentials, and change behavior -- without telling you. You often find out in production.

git-lrc is your braking system. It hooks into git commit and runs an AI review on every diff before it lands. 60-second setup. Completely free.

In short, git-lrc helps Prevent Outages, Breaches, and Technical Debt Before They Happen

At a glance: 10 risk categories · 100+ failure patterns tracked · every commit…

Top comments (0)