1.142 Flashcard Systems & Integrations#
Creating, driving and reading spaced-repetition card collections: genanki, AnkiConnect, ankipandas and Anki’s own library, sorted by who owns the schedule.
At a glance#
| Library | Best for | Verdict | Latest release |
|---|---|---|---|
| genanki | Any program whose job ends when the cards exist | The category default, and not a close call — an order of magnitude more downloads than anything else that is not the application itself. Writes a .apkg and stops: no scheduling, no review history, no runtime dependency on Anki, and MIT so it imposes nothing on the caller. The only decision with lasting consequences is note GUID design, which is what lets a re-issued deck update cards in place instead of orphaning the reader’s history. No release since 2023, but its target has not moved either. | 0.13.1 · 2023-11-12 |
| anki (official library) | Anything that must read or write review history | Technically the most capable option in the category and the only one under active release, and it is passed over at scale anyway. The AGPL’s network clause reaches hosted services, which rules it out for most commercial work; the license, not the API, is where this category divides. Also has no API stability contract — it is an application’s internals that happen to be importable. Was listed for evaluation in the original pass and never evaluated. | 26.8.1 · 2026-09-04 |
| AnkiConnect | Automating your own collection on your own machine | The only path to live, two-way access to someone’s collection without an AGPL dependency in your process — which is genuinely useful and why it persists. Upstream repository ARCHIVED 2025-11-04, which matters more here than usual because it is a compatibility shim against an application that ships monthly. Requires Anki running, an add-on installed, and a desktop. The Python client is separately maintained; a live client does not make an archived server maintained. | — |
| ankipandas | Questions about a collection rather than changes to one | Loads the collection into pandas with the joins already done, which is the first afternoon of any analysis project. Writing is deliberately disabled — modifying a live collection database behind the application’s back is how collections get corrupted. Not a competitor to genanki: a deck writer and a collection reader are complements, and ranking them against each other was the original pass’s structural mistake. | 0.3.15 · 2023-10-11 |
| no integration library (own the schedule) | When the review experience is the product | A scheduler from 1.141 plus your own tables. The algorithm is the small part — SM-2 is ~50 lines, FSRS ~100-200, and there is a maintained package for it. The queue builder is where estimates fail: new-card throttling, daily caps, sibling burying and learning steps are the difference between a session people return to and one they abandon. Highest lock-in in the category, chosen deliberately. Ship a genanki export path early; it costs a day and removes the strongest objection a prospect can raise. | — |
Latest release observed from PyPI in 2026-09.
What the research found
- The category sorts on one question — who owns the review schedule — into five positions: hand off, drive, read, be the collection, or own everything.
- The license, not the API, is the dividing line. The official anki library is strictly more capable than genanki and serves fewer downloads, because AGPL-3.0-or-later has a network clause and genanki is MIT.
- Review history (the .apkg revlog table) is the only irreplaceable data in a flashcard system. A generated deck ships it empty, so the hand-off position is one-directional by construction.
- Portability is scheduler-dependent: SM-2 state travels as structured columns (cards.ivl, cards.factor), modern FSRS state travels as an opaque string in cards.data. ‘Your data is portable’ is true about the cards and shaky about the schedule.
- The category has one point of failure, not four. Three libraries have not released in ~3 years and one is archived; all of them work because Anki’s import path has stayed permissive, so switching libraries does not diversify the risk.
Explainer
Domain Explainer: Flashcard Systems & Integrations#
For someone who has never built one. Every term is defined before it is used.
The Hardware-Store Version#
A hardware store sells fasteners and it sells the things fasteners hold together. Both are useful; they are not substitutes; and someone who walks in asking for “something to join these” needs to be told which shelf they are standing in front of.
This category is the fasteners. It is the set of libraries that let a program put cards into — or get information out of — a spaced-repetition system: an application that shows you a question, asks you to recall the answer, and then decides when to show it to you again.
The deciding-when-to-show-it-again part is a different shelf. That is a scheduling algorithm, and it is surveyed separately in 1.141. This survey is about the plumbing around it: how a program creates cards, how it reaches an existing collection, and who ends up responsible for the results.
Vocabulary, in Dependency Order#
Each term below is used by the ones after it.
Card — one prompt and one answer. “puella” → “girl”. The unit a person actually reviews.
Note — the underlying fact, which may produce several cards. The pair (puella, girl) is one note; it can generate a recognition card (see the Latin, recall the English) and a recall card (the reverse). Editing the note fixes both cards.
Note type (or model) — the template that turns a note into cards. It declares which fields exist (“Latin”, “English”) and which cards to build from them. Changing a note type changes every card made from it.
Deck — a named group of cards. Purely organizational.
Collection — everything one person has: all their notes, cards, decks, settings, and their entire review history. This is the thing that lives on someone’s computer and matters to them.
Review — one answered card. The person saw a prompt, tried to recall, and graded themselves.
Review history — every review ever performed, with its timestamp and grade. This is the important one, and the rest of the explainer keeps coming back to it.
Scheduling algorithm — the rule that reads a card’s past reviews and decides the next date. SM-2 (1988) and FSRS (2023) are the two that matter. See 1.141.
Interchange format — a file that moves cards between programs. In this
category it is .apkg, and one program defines what that means.
The One Fact That Organizes Everything#
Cards are cheap. Review history is irreplaceable.
If you lose a deck of ten thousand cards, you regenerate it from your source data in an afternoon. If you lose someone’s review history — which cards they struggled with, over two years, at what intervals — nothing brings it back. There is no backup source. The person would have to re-learn the material to recreate the record of having learned it.
Every meaningful difference between the libraries in this survey is a difference in who is holding that history.
The Boundary Test#
When someone says “I want to add flashcards to my program”, they are actually choosing among five positions. The question that separates them:
Who owns the review schedule?
1. Hand it away#
Your program writes a file. Someone else’s application opens it and takes over completely — scheduling, reviewing, syncing, backing up. You never hear from it again.
Library: genanki. Cost: hours. What you give up: everything after the file, including any knowledge of what happened.
Think of it as printing a workbook. Once it is printed, what the student writes in it is not your business, and you cannot see it.
2. Drive an owner#
Your program talks to somebody else’s application while it is running, adding and changing cards live.
Library: AnkiConnect. Cost: minutes to start, ongoing to maintain. What you give up: portability — the application must be open, on a desktop, with an add-on installed.
Think of it as reaching over someone’s shoulder to write in their workbook. It works because they are sitting right there.
3. Read an owner#
Your program looks at a collection and answers questions about it. It cannot change anything.
Library: ankipandas. Cost: about an hour. What you give up: nothing — you were never going to write.
Think of it as reading the workbook to see how the student is doing.
4. Be the owner, in someone else’s format#
Your program uses the actual application’s own code as a library, so it can read and write everything, including review history.
Library: the official anki package. Cost: half a day, plus a license
conversation. What you give up: freedom, in a specific legal sense explained
below.
5. Own everything yourself#
No integration library at all. Your program keeps its own cards, its own review records, calls a scheduling algorithm directly, and shows its own interface.
Library: none — a scheduler from 1.141 and your own database. Cost: weeks. What you give up: the option of not maintaining a review system forever.
Why the Cheap Option Is Usually Right#
Position 1 looks like the weakest — you write a file and lose all visibility. In practice it is the correct choice for most programs, for one reason:
The hard parts of a review system are exactly the parts you are handing away.
- Deciding what is due today is not
WHERE due <= today. It needs limits on new cards per day, caps on total reviews, suppression of near-duplicate cards from the same note, and multi-step introduction of unseen material. Without those, a session shows forty variations of one fact and then nothing for three days, and people stop. - Syncing across devices is its own project. People review on a phone, in a queue, for four minutes.
- Backup of irreplaceable data is a responsibility, not a feature.
- And someone has already built all of it, tested it against millions of users, and given it away.
Handing that off is not settling. It is recognizing which shelf you are standing in front of.
The .apkg File, Demystified#
The interchange format is a ZIP archive. Rename one to .zip and open it,
and you find:
collection.anki2— a SQLite database (a whole relational database in a single file)media— a small JSON file- files named
0,1,2, … with no extensions
The numbered files are your images and audio. They were renamed to integers, and
the media JSON is the only record of what they used to be called. This
surprises everyone the first time.
Inside the database are five tables. Three matter:
notes— the contentcards— the schedule: when each card is next due, and the state the scheduling algorithm needsrevlog— the review history, one row per answered card, ever
A file produced by a program has a full notes table, a cards table at
default values, and an empty revlog. That emptiness is the whole meaning
of position 1: a generated deck has not been reviewed by anyone, and nothing
about the reviewing comes back.
The Trap in the Schema#
This is the survey’s least obvious finding, and it contradicts a claim people make casually.
The cards table stores scheduling state in two named columns: ivl (the
current interval in days) and factor (how easy the card has proved). Those two
numbers are exactly what SM-2, the 1988 algorithm, needs — the format was
built around it.
FSRS, the modern algorithm, tracks three different quantities that do not
fit two columns. So they are stored as text in a general-purpose data column
that nothing outside the reference implementation promises to interpret.
The consequence, plainly:
A collection scheduled by the old algorithm is portable. A collection scheduled by the new one is portable only to programs that agree on how to read an unspecified string.
Which means: “your data is portable” is true about the cards and shaky about the schedule. Anyone making that promise should know which half they mean.
The License Wall#
The most capable library here — the application’s own code, published as anki
— is under AGPL-3.0-or-later.
For a non-lawyer, the relevant bit is: the AGPL is a copyleft license with a network clause. Ordinary copyleft says “if you give someone this program, give them the source too”. The AGPL adds “…and running it as a service that people use over a network counts as giving it to them”.
So:
- Using it in a script on your own machine: the license asks nothing.
- Using it in an internal tool nobody outside your organization reaches: nothing.
- Using it inside a hosted product: this is the case the clause exists for, and it is a real question to take to a lawyer rather than to a library comparison.
This single fact explains an otherwise strange pattern in the download numbers.
genanki — third-party, no release since 2023, strictly less capable — serves
more downloads than the official library. It is MIT-licensed, and for a large
population of users that decides it.
The license, not the API, is where this category actually divides.
What “Maintained” Means Here#
Three of the four libraries have not published a release in nearly three years, and a fourth is archived. That sounds alarming and mostly is not, for a reason worth internalizing:
They are aiming at something that is not moving. The file format has been stable for years, so a writer that got it right in 2023 still gets it right. A library whose job can be finished is allowed to look finished.
The risk that matters is subtler, and it is shared rather than distributed: all of them work for the same reason — the application’s import path stays permissive — so having four libraries does not give you four independent bets. It gives you one bet, held four times.
The cheap hedge is to keep a copy of the schema. It is five tables. The difference between “our deck writer broke” and “our deck writer broke and nobody here knows what it was writing” is a page of SQL in your own repository.
Which Shelf Are You Standing In Front Of?#
Three questions, in order. The first one that gets a “yes” is your answer.
1. Is the reviewing experience part of what you are making? Yes → own everything (position 5). Take a scheduler from 1.141, and budget for the queue logic rather than the algorithm; the algorithm is the small part.
2. Does anything need to come back — do you need to know how the cards performed? Yes → you need review history, which means the official library and its license, or your own system. Position 1 cannot report back, ever.
3. Otherwise?
Write a .apkg with genanki. Spend the saved weeks on the content, which is the
part only you can produce.
Related Surveys#
- 1.141 Spaced Repetition Algorithms — the schedulers themselves: SM-2, SM-18, FSRS, LECTOR, what each stores, and what SuperMemo’s licensing costs
- 1.140 Classical Language Libraries — an example of the kind of pipeline that ends up needing this category: content generated upstream, cards downstream
S1: Rapid Discovery
anki - The Official Python Library#
PyPI Package: anki
GitHub: ankitects/anki
Purpose: The collection layer Anki itself is built on — notes, cards,
scheduling, database, sync
Position on the boundary test: IS the application that owns the schedule
Popularity Metrics#
Verified against PyPI and GitHub on 2026-08-25.
- Downloads: 185,160/month (PyPI)
- GitHub Stars: 30,031 (the Anki repository)
- Latest Version: 26.8.1, published 2026-08-05
- Repository activity: pushed the same day this was verified
- License: AGPL-3.0-or-later
- Python:
>=3.10
Why It Was Missing#
This library was listed in this survey’s own evaluation plan and then never
evaluated — the survey compared three third-party packages and stopped. That is
a real hole, because anki is the second most-downloaded package in the
category and the only one released this year.
Quick Assessment#
Pros:
- ✅ Official and actively released — versioned in lockstep with the desktop application, so the format can never drift out from under it
- ✅ The whole collection layer — creating notes is a small part of what it exposes; it also owns the scheduler, the database schema, and sync
- ✅ The only library here that can both read and write review history
- ✅ Enormous project behind it — 30k stars, continuous development
Cons:
- ❌ AGPL-3.0-or-later. This is the decisive fact and it is a license
question, not a technical one: linking a hosted service against AGPL code
carries source-provision obligations that a
.apkgwriter under MIT does not. Teams reach for genanki over this library far more often than the download numbers alone would suggest, and the license is usually why. - ❌ No API stability contract. It is the internals of an application that happens to be importable. Version numbers follow the desktop release, and nothing promises that a private helper survives the next one.
- ❌ Heavy — pulls the machinery of a full application into a process that may only have wanted to write a file
- ❌ Sparse standalone documentation — the documented surface is AnkiConnect’s and the add-on API’s; using the library directly means reading the application’s source
Category Role#
Own the schedule, inside someone else’s collection format. This is the option for a program that needs the review history to be first-class — reading what happened, writing back what happened, and remaining compatible with the application the user already has.
It occupies an unusual position: it is simultaneously the most capable option in the category and the one with the most binding constraint attached. The license, not the API, is what makes it a narrow choice.
Basic Usage#
from anki.collection import Collection
col = Collection("/path/to/collection.anki2")
deck_id = col.decks.id("Latin Vocabulary")
model = col.models.by_name("Basic")
note = col.new_note(model)
note["Front"] = "puella"
note["Back"] = "girl"
col.add_note(note, deck_id)
col.save()
col.close()Confidence as a Default Choice#
MEDIUM — technically the most capable library in the category, and the right answer whenever review history must be read or written. Ruled out for most commercial work by AGPL-3.0-or-later, and for most casual work by weight.
Sources#
- anki PyPI
- ankitects/anki GitHub
- PyPI Stats — 185,160 downloads/month
AnkiConnect - Live Integration With a Running Anki#
Type: Anki add-on (not a PyPI package)
GitHub: FooSoft/anki-connect
Python client: ankiapi on PyPI
Purpose: RESTful API exposing a running Anki desktop to other programs
Position on the boundary test: drives an application that owns the schedule
Popularity Metrics#
Verified against GitHub and PyPI on 2026-08-25.
- Anki Add-on ID: 2055492159
- GitHub Stars: 2,079
- Repository status: ARCHIVED, last push 2025-11-04
- API Port:
localhost:8765 - Python client:
ankiapiv0.2.1, published 2026-04-16, 147 downloads/month
The Maintenance Finding#
The upstream repository is archived. FooSoft/anki-connect was archived on GitHub with its last push on 2025-11-04, which means the canonical source of the add-on is now read-only: no issues, no pull requests, no releases.
This matters more here than it would for an ordinary library. AnkiConnect is a
compatibility shim between two moving targets — the calling program and a
desktop application that ships a new version most months (anki 26.8.1 landed
2026-08-05). A shim that has stopped moving while the thing it wraps has not is
a maintenance liability with a clock on it, even while it still works.
Two things to be clear about:
- The Python client is not the add-on.
ankiapion PyPI was published in April 2026 and is maintained; it speaks to whatever add-on is installed. A live client does not make an archived server maintained. - The AnkiWeb listing state could not be verified for this survey — the
add-on catalog requires JavaScript and was not readable from a plain HTTP
fetch. The archive status above is the GitHub repository’s, which is what was
actually checked. Anyone depending on this should check the AnkiWeb listing
and the forks (
Soki-Team/Anki-Connect-Pluswas the most recently touched at the time of writing, and is small) before committing.
Quick Assessment#
Pros:
- ✅ Live integration — add and update cards in a running collection
- ✅ Full feature reach — most of what the application can do is exposed
- ✅ Bi-directional — reads as well as writes, unlike a file export
- ✅ Established — a large add-on ecosystem was built against this API, which is itself a reason the API is unlikely to disappear quietly
Cons:
- ❌ Archived upstream (see above)
- ❌ Anki must be running — the desktop application is a hard dependency at runtime, not just at import time
- ❌ The reader must install the add-on — the highest-friction requirement in the category
- ❌ Desktop only — there is no mobile equivalent
- ❌ More moving parts than a file — a local HTTP service, an add-on version, and an application version all have to agree
Category Role#
Drive: the only position that gets live, two-way access to a collection the reader already owns without taking on the AGPL obligation of the official library. That combination is useful, and is why the add-on persists.
The cost is that it works only on a desktop, with the application open, after the reader has installed something. Every one of those is a place the integration stops working through no fault of the calling program.
API Example#
# Install: pip install ankiapi
from ankiapi import AnkiAPI
api = AnkiAPI() # Connects to localhost:8765
# Create deck
api.create_deck("Latin Vocabulary")
# Add flashcard
api.add_flashcard(
deck="Latin Vocabulary",
front="puella",
back="girl"
)Confidence as a Default Choice#
LOW as a default, HIGH for its one job. For emitting cards, a .apkg file
is strictly less trouble. For a tool that has to observe and modify a
collection while its owner is using it, this is the only option that does not
require an AGPL dependency — and the archive status should be checked before it
is chosen.
Sources#
- AnkiConnect Add-on
- FooSoft/anki-connect GitHub — archived 2025-11-04
- ankiapi PyPI — v0.2.1, 2026-04-16
ankipandas - Collection Analysis#
PyPI Package: ankipandas
GitHub: klieret/AnkiPandas
Purpose: Load an Anki collection into pandas DataFrames
Position on the boundary test: reads a schedule someone else owns
Popularity Metrics#
Verified against PyPI and GitHub on 2026-08-25.
- Downloads: 275/month (PyPI)
- GitHub Stars: 155
- Latest Version: 0.3.15, published 2023-10-11
- Repository activity: last push 2026-08-03 — still tended, not released
- License: MIT
Two corrections to this survey’s original entry, both verified above: the license is MIT (it was recorded as “not specified”), and the download figure is 275/month, not the 1,548 recorded in 2025. Usage fell; it did not grow.
Quick Assessment#
Pros:
- ✅ Pandas integration — the collection becomes a DataFrame, and every analysis tool a Python user already knows applies to it
- ✅ Good at its one job — “which cards are hardest”, “what does my retention curve actually look like”, “where did the last six months go”
- ✅ Export — CSV, Excel, HTML, JSON
- ✅ MIT, and the repository is still receiving commits
Cons:
- ❌ Writing is disabled (upstream issue #137). This is a deliberate decision, not a gap: writing to a live collection database behind the application’s back is how collections get corrupted.
- ❌ No release since 2023-10-11
- ❌ Small — 275 downloads/month against genanki’s 269,751
Category Role#
Read. It is the only library here whose purpose is to answer questions about a collection rather than to change one, and it is the natural companion to any of the other three rather than a competitor to them.
Reading it as a weak alternative to genanki — which is how it was originally recorded here, at a “22× popularity” disadvantage — compares two tools that do not do the same thing. A deck writer and a collection reader are not ranked against each other; a program can easily need both.
What It Is Not#
It cannot create cards. If the requirement is “produce a deck”, this is the wrong library and no amount of it will help.
Basic Usage#
from ankipandas import Collection
# Load Anki collection
col = Collection()
# Analyze as DataFrame
notes_df = col.notes.fields_as_columns()
cards_df = col.cards.merge_notes()
# Export analysis
cards_df.to_csv('analysis.csv')Confidence as a Default Choice#
HIGH for analysis, N/A for generation. The right tool for reading a collection; not a candidate for writing one.
Sources#
S1: Rapid Discovery - Approach#
Methodology: Rapid Library Search (speed-focused) Time Box: 60-90 minutes maximum Goal: Map the libraries that let a program create, drive or read a spaced-repetition card collection, and find the default among them
The Boundary Test#
Every library in this category is answering one question, and the answer sorts them cleanly:
Who owns the review schedule?
- The library hands the schedule away. It produces a file or a payload and something else — usually Anki — decides when each card comes back. genanki.
- The library drives an application that owns the schedule. It is a client for a scheduler running somewhere else. AnkiConnect.
- The library reads a schedule someone else owns. It can see the state and cannot change it. ankipandas.
- The library IS the application that owns the schedule. It is the whole
collection layer, scheduler included. Anki’s own
ankipackage. - Your code owns the schedule. No integration library at all — an algorithm from 1.141 plus a table of your own.
This is the boundary that matters because it decides who is responsible for the review history, and review history is the only thing in a flashcard system that cannot be regenerated. Everything else — the cards, the templates, the media — can be rebuilt from source data in an afternoon.
Core Philosophy#
Quickly map the solution space:
- What card-collection libraries exist, and what does each one own?
- How mature and how widely used is each?
- Where does the interchange format sit, and how stable is it?
- What’s the 80/20 answer?
Discovery Process#
1. Landscape Scan (25 min)#
- genanki: programmatic
.apkggeneration, no Anki required - anki: the official Python library — the whole collection layer
- AnkiConnect: RESTful API against a running Anki desktop
- ankipandas: read a collection into pandas
- Check: PyPI downloads, GitHub stars, release recency, license
2. Own-The-Schedule Patterns (20 min)#
- FSRS or SM-2 (see 1.141) over SQLite — the simplest build-your-own
- Web frameworks driving an algorithm directly
- Existing open-source review applications
- Implementation complexity estimate
3. Ecosystem Assessment (15 min)#
- Size of the installed base the interchange format targets
.apkgformat stability (future-proofing)- Sync options for collections that leave the desktop
- Community momentum: growing or declining
4. Quick Comparison (15 min)#
- Hand-off vs drive vs read vs own: effort and friction for each
- Where the hybrid combinations are real and where they are traps
5. Initial Recommendation (10 min)#
- The default for each position on the boundary test
- When to consider alternatives
- Signal for S3 persona analysis
Evaluation Criteria#
Primary:
- Implementation effort (hours to a working card-delivery path)
- Adoption friction for the person who ends up reviewing the cards
Secondary:
- Data portability — can the review history be exported and reinterpreted?
- Long-term maintenance burden, including the license
Tertiary:
- Interface control versus ecosystem reach
Output Files#
approach.md(this file)genanki.md— programmatic deck generationanki-pylib.md— the official libraryankiconnect.md— live integration with a running Ankiankipandas.md— read-only collection analysisrecommendation.md— the S1 default
Success Criteria#
- Understand the integration options (4 viable libraries)
- Estimate own-the-schedule complexity (rough hours)
- Identify which position minimizes friction, and for whom
- Provide input for S3 persona analysis
- Total time:
<90minutes
Note for S3#
S3 does the heavy lifting on who is choosing and why. S1 maps what is possible; S3 works out which position on the boundary test a given constraint forces, and S4 works out what each position costs to leave.
genanki - Programmatic Anki Deck Generation#
PyPI Package: genanki
GitHub: kerrickstaley/genanki
Purpose: Generate Anki .apkg files without an Anki installation
Position on the boundary test: hands the schedule away
Popularity Metrics#
Verified against PyPI and GitHub on 2026-08-25.
- Downloads: 269,751/month (PyPI)
- GitHub Stars: 2,678
- Latest Version: 0.13.1, published 2023-11-12
- Repository activity: last push 2024-12-30; not archived
- License: MIT
- Python:
>=3.6
Quick Assessment#
Pros:
- ✅ No Anki dependency — writes
.apkgfiles standalone - ✅ Simple API — Model → Note → Deck → Package →
write_to_file() - ✅ Media support — images and audio embedded in the
.apkg - ✅ GUID management — stable note IDs, so a re-issued deck updates rather than duplicates. This is the feature that separates it from writing the format by hand, and the one most people discover they needed later.
- ✅ The popularity leader by a wide margin — 269,751 downloads/month
- ✅ MIT — permissive, no copyleft obligation on the calling program
Cons:
- ⚠️ No release since 2023-11-12 — nearly three years at the time of writing. The repository was still receiving commits into late 2024 and is not archived, so this reads as a finished library rather than an abandoned one, but nothing has shipped from it in a long while.
- ⚠️ Not official — no affiliation with the Anki project, so format changes reach it second-hand
- ⚠️ No scheduling — it creates cards; something else decides when they come back
- ⚠️ The reader needs Anki — an
.apkgis only useful to someone who has an application that can open one
Category Role#
Hand-off: genanki is the reference implementation of the hand-off position. It converts structured data into the interchange format and stops. Everything after the file is written — scheduling, review UI, sync, statistics, backup — belongs to whatever opens it.
That is a feature and not a limitation, and it is the reason this is the default for most programs that need to emit cards: the hardest parts of a review system are the parts genanki refuses to do.
It is not an option for a program that must own the schedule. There is no
partial credit here: a .apkg writer cannot be grown into a review application.
Basic Usage#
import genanki
# Create model (card template)
model = genanki.Model(...)
# Create notes
note = genanki.Note(model=model, fields=['Latin', 'English'])
# Create deck
deck = genanki.Deck(deck_id=123, name='Latin Vocabulary')
deck.add_note(note)
# Export to .apkg
genanki.Package(deck).write_to_file('output.apkg')Confidence as a Default Choice#
HIGH — for any program whose job ends when the cards exist. Not applicable — for a program that must own the review schedule.
Sources#
- genanki PyPI
- genanki GitHub
- PyPI Stats — 269,751 downloads/month
S1 Rapid Discovery - Recommendation#
Time Spent: ~75 minutes Confidence Level: HIGH (for the library landscape)
The Category, Sorted by Who Owns the Schedule#
All figures verified against PyPI and GitHub on 2026-08-25.
| Library | Owns the schedule? | Downloads/mo | Latest release | License | Verdict |
|---|---|---|---|---|---|
| genanki | No — hands it to Anki | 269,751 | 0.13.1 (2023-11) | MIT | ✅ The default |
| anki (official) | Yes — it is the collection | 185,160 | 26.8.1 (2026-08) | AGPL-3.0+ | ⚠️ Capable, license-bound |
| AnkiConnect | No — drives a running Anki | 147 (ankiapi client) | client 0.2.1 (2026-04) | — | ⚠️ Upstream archived |
| ankipandas | No — reads only | 275 | 0.3.15 (2023-10) | MIT | ✅ For analysis, not creation |
The Default: genanki#
For the common case — a program that has content and needs it to become reviewable cards — genanki is the answer, and the popularity signal is not close: 269,751 downloads/month, an order of magnitude above everything else in the category that is not the application itself.
Why genanki wins:
- ✅ Decisive adoption
- ✅ Simple API (Model → Note → Deck → Package)
- ✅ No Anki installation required — it writes the file, nothing more
- ✅ MIT, so it imposes nothing on the calling program
- ✅ Media support, and GUID management so re-issued decks update in place
What it costs: everything after the file. Scheduling, review interface,
sync, statistics and backup all belong to whatever opens the .apkg. For most
programs that is the point.
When the Default Is Wrong#
- The review history has to be read or written → the official
ankipackage is the only library that can, and AGPL-3.0-or-later is the price. - A collection has to be changed while its owner is using it → AnkiConnect, with the archive status checked first.
- The question is about a collection rather than about cards → ankipandas.
- The schedule must belong to your own application → none of these. That is an algorithm decision, and it is 1.141’s subject, not this survey’s.
Corrections to the Original S1#
This pass was re-verified on 2026-08-25 and three of its recorded facts had moved or were wrong:
- genanki’s adoption was understated by 8× — 269,751/month, not 33,970.
- AnkiConnect is not “active” — the upstream repository is archived as of 2025-11-04. Its Python client is separately maintained; that is not the same thing.
- ankipandas is MIT (recorded as “not specified”) and its usage fell to 275/month from the 1,548 recorded.
A fourth correction is structural rather than factual: the original headline —
“genanki is the clear winner, 22× more popular than alternatives” — ranked a
deck writer against a collection reader, which are not alternatives to each
other. The comparison that decides anything is the one in the table above, and
it needed the official anki package in it, which the original pass listed for
evaluation and never evaluated.
Quick Validation#
Basic usage (confirmed from docs):
pip install genanki
import genanki
model = genanki.Model(...)
note = genanki.Note(model=model, fields=['Latin', 'English'])
deck = genanki.Deck(deck_id=123, name='Latin')
deck.add_note(note)
genanki.Package(deck).write_to_file('output.apkg')Generates: a .apkg file that any Anki client can import.
What S1 Did NOT Answer#
S1 is library discovery. These belong to the later passes:
For S2 (Comprehensive):
- What is actually inside a
.apkg, and how stable is that container? - How the four libraries differ in what they can express, not just in adoption
- The license boundary in detail: what AGPL-3.0-or-later obliges, and when
For S3 (Need-Driven):
- Which constraint forces which position on the boundary test
- Effort comparison: hand-off versus drive versus own
For S4 (Strategic):
- What each position costs to leave, and what happens to review history when you do
- Single-implementation risk in the interchange format
Sources#
- genanki PyPI — 269,751 downloads/month
- genanki GitHub — 2,678 stars
- anki PyPI — 185,160 downloads/month, v26.8.1
- ankitects/anki GitHub — 30,031 stars
- AnkiConnect — add-on
- FooSoft/anki-connect GitHub — archived 2025-11-04
- ankipandas PyPI — 275 downloads/month
- FSRS PyPI — the schedule-owning path; see 1.141
- Awesome FSRS
S2: Comprehensive
The Official anki Library, and the AGPL Boundary#
What it is: the collection layer of the Anki application, published to PyPI
as anki and versioned with the desktop release. Version 26.8.1 was published
2026-08-05.
What It Can Reach#
Everything in apkg-format.md, as objects rather than as tables:
from anki.collection import Collection
col = Collection("/path/to/collection.anki2")
# Create
deck_id = col.decks.id("Latin Vocabulary")
note = col.new_note(col.models.by_name("Basic"))
note["Front"], note["Back"] = "puella", "girl"
col.add_note(note, deck_id)
# Read the schedule and the history — the part nothing else here can do
card = col.get_card(col.find_cards("deck:'Latin Vocabulary'")[0])
print(card.ivl, card.factor, card.reps, card.lapses)
col.save()
col.close()It owns the scheduler, the search language, the sync client, the import and export paths, and the database migrations. It is not an integration library; it is the application, importable.
The Capability Nothing Else Has#
Review history, both directions. revlog is readable and writable through
this library and through nothing else in the category. genanki writes it empty,
ankipandas reads it but cannot write, and AnkiConnect exposes a filtered view
through an add-on that is now archived.
If the requirement is “import a reader’s existing history”, “migrate a collection between scheduling algorithms”, or “compute something from what actually happened and write the result back”, this is the only option.
The License Boundary#
anki is AGPL-3.0-or-later. This is the fact that decides most adoption
decisions in the category, and it deserves stating exactly rather than as
folklore.
- The AGPL is the GPL plus a network clause. Conveying the program obliges you to offer corresponding source, and so does making it available to users over a network — which is what a hosted service does. There is no “we did not distribute a binary” defense.
- The obligation attaches to the combined work. A service that imports
ankiin-process is the case the network clause was written for. - The usual mitigation is process isolation: run the AGPL code as a separate program and talk to it over a defined interface, so the combined-work argument is at least contestable. Whether that separation is sufficient is a legal question with an unsettled answer, and this survey is not the place to resolve it. Get advice; do not get it from a library comparison.
- None of this applies to internal or personal use. A script on your own machine, a research pipeline, an in-house tool nobody outside the organization reaches — the AGPL asks nothing of any of them.
This is why the download figures read the way they do. genanki serves 269,751
downloads a month against anki’s 185,160, despite anki being strictly more
capable, official, and the only one released this year. MIT versus AGPL is most
of that gap.
The Other Cost: No API Contract#
The version number tracks the desktop application. There is no published stability policy for the Python surface, no deprecation cycle, and the documentation that exists documents the add-on API rather than the library. Using it means reading the application’s source and accepting that a helper you depend on may be refactored in the next monthly release.
For a pipeline you control and re-run, that is a manageable cost. For a product shipped to people who will run old versions, it is not.
Sources#
- anki PyPI — v26.8.1, AGPL-3.0-or-later, Python
>=3.10 - ankitects/anki GitHub
- GNU AGPL v3 — §13, the network clause
AnkiConnect: the Live-Drive Path#
What it is: an Anki add-on that runs an HTTP server on localhost:8765
inside the desktop application, accepting a JSON action envelope and executing
it against the open collection.
The Protocol#
One endpoint, one shape:
import json, urllib.request
def invoke(action, **params):
payload = json.dumps({"action": action, "version": 6, "params": params})
req = urllib.request.Request("http://127.0.0.1:8765", payload.encode())
response = json.load(urllib.request.urlopen(req))
if response["error"] is not None:
raise RuntimeError(response["error"])
return response["result"]
invoke("createDeck", deck="Latin Vocabulary")
invoke("addNote", note={
"deckName": "Latin Vocabulary",
"modelName": "Basic",
"fields": {"Front": "puella", "Back": "girl"},
"tags": ["latin"],
})Every response is {"result": ..., "error": ...} with exactly one of the two
populated. The version field is part of the request, which is unusually
careful for an add-on API and is why so much has been built against it.
ankiapi on PyPI (v0.2.1, 2026-04-16) is a thin convenience wrapper over
exactly this. It is separately maintained from the add-on.
What It Can Do That Nothing Else Can#
Reach a collection that someone else is using, while they are using it, without an AGPL dependency in your process. The add-on carries the license obligation; your program is an HTTP client.
That combination — live, two-way, no copyleft in your binary — is the whole reason this exists, and nothing else in the category offers it.
Failure Modes#
The integration has more places to fail than any other option here, and each is outside the calling program’s control:
| Failure | Cause | What the caller sees |
|---|---|---|
| Connection refused | Anki is not running | URLError on connect |
| Connection refused | Add-on not installed | Same — indistinguishable |
| Hangs | A modal dialog is open in Anki | Request never returns |
error populated | Deck or model name does not exist | Error string, no code |
| Wrong collection | The reader has multiple profiles | Silently writes to the open one |
| Nothing at all | The reader is on mobile | There is no mobile equivalent |
Two of these deserve emphasis. A modal dialog blocks the API — Anki is a desktop application first, and if the reader has a dialog open the server does not answer. And errors are strings, not codes, so a caller distinguishing “deck missing” from “model missing” is matching on English prose.
The Maintenance Finding#
The upstream repository, FooSoft/anki-connect, is archived on GitHub with
its last push on 2025-11-04. Read-only: no issues, no pull requests, no
releases.
The weight of that depends on what AnkiConnect is. It is a compatibility shim between a caller and a desktop application that ships roughly monthly. A shim that has stopped moving while the thing it wraps has not is a liability with a clock on it, even while it still works — and it does still work.
What was not verified for this survey: the AnkiWeb add-on catalog requires
JavaScript and could not be read from a plain fetch, so the listing’s current
state is unknown here. Forks exist and are small; Soki-Team/Anki-Connect-Plus
was the most recently touched at the time of writing, at 20 stars. Anyone
choosing this path should check the listing and the fork landscape themselves
rather than take a survey’s word for it.
Sources#
- FooSoft/anki-connect GitHub — archived 2025-11-04, 2,079 stars
- AnkiConnect add-on listing — listing state not verified
- ankiapi PyPI — v0.2.1, 2026-04-16
ankipandas: the Read Path#
What it is: a loader that turns the SQLite tables in apkg-format.md into
pandas DataFrames, with the joins already done.
What It Gives You#
from ankipandas import Collection
col = Collection() # finds the local collection
notes = col.notes.fields_as_columns() # flds exploded into real columns
cards = col.cards.merge_notes() # cards joined to their notes
reviews = col.revs.merge_cards() # every review, with its cardThe value is in those three calls. Working against the raw schema means
splitting flds on a separator, resolving mid against a JSON blob in col,
and joining revlog.cid by hand. ankipandas does all of it and hands back
something a person can groupby.
What It Is For#
Questions about a collection, which are a different kind of question from anything the other three libraries answer:
- Which cards account for most of the review time? (
revs.time) - What does the lapse distribution look like, and which notes dominate it?
- Did the interval growth change after a scheduler switch? (
revs.ivloverrevs.id, which is the review timestamp) - How much of the collection has never been seen?
These need revlog, and revlog is exactly what a generated deck does not
have. That is the clean division of labor in this category: genanki writes
decks forward, ankipandas reads history back, and they are complements rather
than competitors.
Writing Is Disabled On Purpose#
Write support is off (upstream issue #137). This is a decision rather than a gap, and it is the right one: modifying a live collection database behind the application’s back, while it may be open, is how collections get corrupted. Anki’s own library takes the collection lock; a pandas layer would not.
The practical consequence: ankipandas is an analysis tool, and any pipeline that reads with it and then needs to write must write through something else.
Maintenance Posture#
- Last PyPI release 0.3.15, 2023-10-11
- Repository last pushed 2026-08-03 — still tended
- MIT license, 155 stars, 275 downloads/month
The pattern is the mirror image of genanki’s: a repository that is still alive paired with a release that is nearly three years old. Both packages are stable against a stable schema. The exposure is the same in both cases — if the schema moves, someone has to ship.
Two corrections to the original S1 record, both verified 2026-08-25: the license is MIT, not “not specified”, and downloads are 275/month, not the 1,548 recorded — usage fell rather than grew.
Sources#
- AnkiPandas GitHub — MIT, 155 stars
- ankipandas PyPI — v0.3.15
- ankipandas documentation
The Interchange Format: What Is Inside a .apkg#
Everything in this category is organized around one file format. Here is what
that file is. The description below was read out of
genanki’s writer (package.py) and schema (apkg_schema.py) rather than
summarized from documentation.
The Container#
A .apkg is a ZIP archive. genanki writes exactly three kinds of member
into it:
| Member | What it is |
|---|---|
collection.anki2 | A SQLite database — the collection |
media | A JSON object mapping "0", "1", … to original filenames |
0, 1, 2, … | The media files themselves, renamed to their index |
The media indirection is the part that surprises people: images and audio are
stored under integer names and the media JSON is the only thing that remembers
what they were called. Unzip a .apkg by hand and you get a pile of
extension-less numbered files.
The Tables#
collection.anki2 carries five tables: col, notes, cards, revlog and
graves.
col— one row. Collection-level configuration: models (card templates), deck list, and settings, mostly as JSON blobs in text columns.notes— the content.guid(a stable identifier),mid(which model),flds(the fields, joined by a separator),sfld(the sort field),tags.cards— the schedule. One note can produce several cards.revlog— the review history. One row per answered card, ever.graves— deletions, so that a sync can propagate them.
The Column That Decides Everything#
cards is where the survey’s central fact lives:
CREATE TABLE cards (
id integer primary key,
nid integer not null, /* note */
did integer not null, /* deck */
ord integer not null,
mod integer not null,
usn integer not null,
type integer not null,
queue integer not null,
due integer not null,
ivl integer not null, /* interval, days */
factor integer not null, /* SM-2 easiness factor × 1000 */
reps integer not null,
lapses integer not null,
left integer not null,
odue integer not null,
odid integer not null,
flags integer not null,
data text not null
);ivl and factor are SM-2 state, first-class columns in the interchange
format. The format was designed around a specific scheduling algorithm — the one
1.141 describes as the 1988 baseline — and that algorithm’s variables are part
of its public shape.
Modern scheduling state does not fit those two columns. FSRS tracks difficulty,
stability and retrievability, which are three quantities with different meanings,
and they live in the free-form data text column rather than in the schema. The
consequence is concrete:
A card’s SM-2 state is structured and portable. Its FSRS state is a string in a column whose contents nothing outside Anki promises to interpret.
That is a lock-in finding hiding in a schema, and S4 picks it up.
The Table Nobody Exports#
revlog is the review history — id is the review’s timestamp in epoch
milliseconds, plus cid, ease (what the reader pressed), ivl, lastIvl,
factor, time (how many milliseconds the answer took) and type.
This is the only irreplaceable data in a flashcard system. Cards can be regenerated from source content in an afternoon; a year of a reader’s actual recall performance cannot be regenerated at all. It is also what every scheduling algorithm needs in order to fit its parameters.
A generated deck has an empty revlog. genanki writes the schema and fills
notes and cards; there is no history to write, because nothing has been
reviewed. That is correct behavior and it is also the reason the hand-off
position is one-directional: a deck goes out, and nothing comes back.
Format Stability#
- The schema above has been recognizably the same for years, which is why a third-party writer that has not shipped a release since 2023 still produces files that current Anki opens.
- Newer Anki versions write their own exports in a newer container —
the collection member may be named
collection.anki21orcollection.anki21band compressed rather than stored, and full-collection exports use a separate.colpkgextension. Importers accept the older layout; this is why writing the 2023-era format is still safe. - The stability is real, and it has one source: there is one implementation that matters. The format is stable because Anki is stable, not because anything specifies it. That is a different kind of guarantee, and S4 treats it as a risk rather than as a comfort.
Sources#
- genanki
package.py— the ZIP writer, read 2026-08-25 - genanki
apkg_schema.py— the SQL schema, read 2026-08-25 - ankitects/anki — the reference implementation
S2: Comprehensive Analysis - Approach#
Research Date: 2026-08-25 (S1 originally 2025-11-23) Focus: What the interchange format can express, what each library can reach, and where the license boundary falls
What This Pass Asks#
S1 ranked the libraries by adoption and sorted them by who owns the review schedule. That is enough to pick a default and not enough to know what a choice commits you to.
S2 goes underneath the packages to the thing they all touch: the collection. Every library in this category is a different amount of access to the same handful of SQLite tables, and almost every difference between them — what they can express, what they can read back, what they cost to leave — falls out of how much of that schema they let you see.
Method#
Primary sources, in this order:
- The format itself. The
.apkgschema in this pass was read out of genanki’sapkg_schema.pyand itspackage.pywriter, not summarized from documentation. Column names and table names below are quoted from that source. - Each library’s own code and published API, for what it can and cannot do.
- Registry and repository metadata — releases, licenses, activity — checked directly against PyPI and GitHub rather than taken from the previous pass. Three of S1’s recorded facts had moved; they are corrected in place and the corrections are listed in S1’s recommendation.
Where a claim could not be verified from a primary source, it says so. The AnkiWeb add-on catalog could not be read without JavaScript, so AnkiConnect’s listing state is reported as unverified while its repository state — archived, 2025-11-04 — is reported as checked.
Structure of This Pass#
apkg-format.md— what is actually inside the interchange file, and which scheduling state travels with itgenanki.md— the hand-off library in depthanki-pylib.md— the official library, and the AGPL boundary in detailankiconnect.md— the live-drive protocol and its failure modesankipandas.md— the read pathown-the-schedule.md— the no-integration-library option, and what it costsrecommendation.md— what the technical picture changes about S1’s default
Scope Boundary#
This survey covers libraries that create, drive or read spaced-repetition card collections. The scheduling algorithms themselves are 1.141’s subject and are not re-derived here; where scheduling state appears below it is because the interchange format carries it, which is a fact about the format.
genanki in Depth#
What it is: a writer for the .apkg format described in apkg-format.md.
It builds a SQLite database in a temporary file, zips it with the media, and
stops.
The Object Model#
Four objects, in a fixed relationship:
import genanki
model = genanki.Model(
1607392319, # model id — MUST be stable across runs
'Latin Vocabulary',
fields=[{'name': 'Latin'}, {'name': 'English'}],
templates=[{
'name': 'Recognition',
'qfmt': '{{Latin}}',
'afmt': '{{FrontSide}}<hr id="answer">{{English}}',
}],
)
note = genanki.Note(model=model, fields=['puella', 'girl'], guid='latin-puella')
deck = genanki.Deck(2059400110, 'Latin Vocabulary')
deck.add_note(note)
genanki.Package(deck, media_files=['puella.mp3']).write_to_file('latin.apkg')- Model — the card template. One model can generate several cards per note (recognition and recall from the same pair, for example) by declaring several templates.
- Note — the content, as a list of field values in the model’s field order.
- Deck — a named container with a numeric id.
- Package — the writer. Takes decks plus a list of media file paths.
The Two Ids That Are Not Decoration#
Both Model and Deck take a numeric id, and both matter more than they look.
Model id: if it changes between runs, Anki treats the new file as declaring a different card type. The reader ends up with two note types that look identical and do not merge. The id must be generated once and then hard-coded — generating it at runtime is the single most common way a generated deck goes wrong, and it produces no error.
Note guid: this is the update key. Anki matches incoming notes to existing
ones by GUID. Set it from something stable in your source data and re-issuing
the deck updates the reader’s existing cards while preserving their review
history. Leave it unset and genanki derives it from the field contents, which
means correcting a typo in a field creates a new note and orphans the old one’s
history.
This is the whole reason to use genanki rather than writing the ZIP yourself: it is the only part of the format where getting it wrong destroys something the reader cannot get back.
What It Can Express#
- Multiple note types, multiple templates per type, conditional templates
- CSS styling per model
- Media: images, audio, anything the reader’s client can render
- Tags
- Deck hierarchies, via
::in deck names
What It Cannot Express#
- Review history.
revloggoes out empty. There is no API for it and the omission is correct — a generated deck has not been reviewed. - Scheduling state.
cards.ivlandcards.factorare written at their defaults. A generated card is a new card. - Anything about a collection that already exists. genanki has no reader. It cannot ask what the reader already has, so it cannot avoid duplicating it except through the GUID mechanism above.
Maintenance Posture#
The version on PyPI, 0.13.1, was published 2023-11-12. The repository received commits into 2024-12-30 and is not archived. 269,751 downloads a month are being served by a package that has not changed in nearly three years.
This reads as a finished library rather than an abandoned one. Its job — write a stable file format — is a job that can be finished, and the format has not moved. The risk is not that the code rots; it is that if the format ever does move, nobody is standing there to follow it. There is one maintainer-shaped hole and 269,751 monthly downloads behind it.
Integration Surface#
Almost nothing. It is a pure function from your data to a file: no daemon, no configuration, no runtime dependency on Anki, MIT-licensed, and it imports cleanly into any process. The entire integration cost of the hand-off position is the code above.
Sources#
Owning the Schedule: the No-Library Option#
The fifth position on S1’s boundary test uses none of these libraries. The program keeps its own cards, its own review records, and calls a scheduling algorithm directly.
This belongs in the survey because it is a real option that people reach for, and because the comparison is usually made badly — against genanki, which does something else entirely.
What It Actually Requires#
The scheduler is the small part. From 1.141: SM-2 is roughly fifty lines of
arithmetic, and an FSRS implementation is on the order of a hundred to two
hundred, with a maintained Python package (fsrs, MIT, 269,751 downloads a
month in its own category) available so nobody has to write either.
What a review system needs beyond the scheduler:
| Piece | Why it is not optional |
|---|---|
| A card store | Two tables, roughly the shape of notes and cards |
| A review log | Append-only; this is the irreplaceable data |
| A review interface | Keyboard-first, or nobody uses it twice |
| A queue builder | “What is due now” is a query with more edge cases than it looks: new-card limits, daily caps, burying siblings, learning steps |
| Sync, or a decision not to | Reviewing happens on whatever device is in reach |
| Import and export | Or the reader’s history is trapped in your product |
| Backup | See above, but worse |
The queue builder is where estimates go wrong. “Show cards where due <= today”
is five minutes of work and produces a review experience people abandon —
without new-card throttling and sibling burying, a session serves forty
variations of the same fact and then nothing for three days.
When It Is Right#
- The review interface is the product. If the scheduling experience is what differentiates you, delegating it to another application is not an option.
- The content cannot be expressed as cards. Anything with per-item interaction beyond front-and-back — audio recording, drawing, code execution — leaves the format behind.
- The platform has no Anki. Web and mobile-web are the clear cases.
- The review history is a first-class product asset, and it must live in your schema rather than in someone else’s file.
When It Is Wrong#
- When the actual requirement was “produce cards”, and the review application the reader already uses would have been fine.
- When the timeline assumes the scheduler was the hard part.
- When nobody has costed sync, and the product ships desktop-only in a category whose users review on a phone in a queue.
The Comparison#
Against genanki this is not a close call in either direction, because they are not the same decision:
Hand off (genanki) | Own it | |
|---|---|---|
| To first working cards | Hours | Weeks |
| Review interface | The reader’s | Yours to build and maintain |
| Sync | The reader’s | Yours |
| Review history | Never yours | Yours, and yours to protect |
| Reader friction | Must have Anki | Must trust you |
| Ceiling | Whatever Anki does | Whatever you build |
The question is not which is better. It is whether the review experience is part
of what you are making. If it is not, the hand-off position is strictly cheaper;
if it is, no amount of .apkg writing will substitute.
Sources#
- 1.141 Spaced Repetition Algorithms — the schedulers, their state and their licensing
- fsrs PyPI — v6.3.2, 2026-08-09, MIT
S2 Recommendation: What the Technical Picture Changes#
S1’s default — genanki, for a program whose job ends when the cards exist — survives S2 intact. What S2 adds is the shape of the decision around it.
The Category Is Four Positions, Not a Ranking#
| Position | Library | The thing it owns |
|---|---|---|
| Hand off | genanki (MIT) | Nothing after the file |
| Own the collection | anki (AGPL-3.0+) | All of it, license attached |
| Drive a running collection | AnkiConnect (archived) | Nothing; borrows the application’s |
| Read a collection | ankipandas (MIT) | Nothing; observes |
A program can need two of these at once and they will not conflict. Ranking them against each other — which is what the original “genanki is 22× more popular” headline did — compares tools that answer different questions.
The Three Findings That Should Change a Decision#
1. The license, not the API, is the boundary. anki is more capable than
genanki in every technical respect and is the only library here released this
year. It is passed over anyway, at scale, because AGPL-3.0-or-later has a
network clause and genanki has MIT. Any comparison that leads with capability
gets this category backwards.
2. Review history is the only irreplaceable thing, and the format treats it
unevenly. revlog carries the reader’s actual recall performance. The
interchange format makes SM-2 state — cards.ivl, cards.factor — structured
and portable, and leaves modern FSRS state in a free-form data text column
that nothing outside the reference implementation promises to interpret. A
collection is portable in proportion to how old its scheduler is.
3. Two of the four are stable-but-unreleased, and one is archived. genanki (2023-11) and ankipandas (2023-10) have both gone nearly three years without a release while their repositories stayed alive; AnkiConnect’s upstream is archived as of 2025-11-04. All of them still work, because the schema they target has not moved. The exposure is shared and singular: the format is stable because one implementation is stable, not because anything specifies it.
Choose By Requirement#
- “Turn this data into cards someone can review.” → genanki. Set stable model ids and note GUIDs; that is the only part where a mistake destroys something the reader cannot recover.
- “Read or write review history.” → the official
ankilibrary, or nothing. Check the license against your deployment before writing code, not after. - “Change a collection while its owner is using it.” → AnkiConnect, having first checked the add-on’s current listing state yourself.
- “Understand what happened in a collection.” → ankipandas.
- “The review experience is the product.” → none of these. Take a scheduler from 1.141 and own the whole stack, with the queue builder — not the algorithm — costed as the hard part.
What S2 Did Not Settle#
Whether process isolation is sufficient to avoid AGPL obligations on a hosted service. It is an unsettled legal question and a library survey is the wrong instrument for it. What the survey can say is where the question arises, which is at every use of the official library in a networked product.
S3: Need-Driven
S3: Need-Driven Discovery - Approach#
Research Date: 2026-08-25 Focus: Who chooses which position on the boundary test, and what forces it
What This Pass Asks#
S2 established what each library owns. S3 asks which constraint decides, because in this category the decision is almost never made on capability.
The pattern that emerges across the personas below: the choice is forced by something outside the code — a license, a device the reader owns, a corpus that already exists, a deadline, or an obligation to hand data back. Two teams with identical technical requirements land on different libraries because one of them ships a hosted service and the other does not.
Method#
Each persona is a WHO with a WHY: a specific constraint that changes the answer, not a market segment. A persona earns its place only if flipping its constraint flips the recommendation.
Effort figures are order-of-magnitude planning numbers derived from the integration surfaces measured in S2 — the size of the code each position requires, not quotes for a project.
Personas Covered#
- The content-pipeline maintainer — has a corpus, needs cards out of it
- The product builder — the review experience is the thing being sold
- The educator — distributing to people who did not choose the tooling
- The learning researcher — the question is about history, not about cards
- The power user — automating their own collection, on their own machine
- The platform integrator — adding review to an existing hosted product
Scope Boundary#
This is a category survey. The personas are the category’s readers, and no one of them is the reason the survey exists. A survey that recommends by persona is doing its job; a survey that recommends one answer has quietly become a memo.
Effort by Position#
Order-of-magnitude planning figures, derived from the integration surfaces measured in S2 — the size of the code each position requires. They are not quotes, and they assume a developer who has read the relevant S2 file first.
To a First Working Result#
| Position | Library | First result | What “first result” means |
|---|---|---|---|
| Hand off | genanki | 1-3 hours | A .apkg that imports cleanly |
| Read | ankipandas | ~1 hour | A DataFrame answering a real question |
| Drive | AnkiConnect | ~30 minutes | A card added to a running collection |
| Own the collection | anki | half a day | Notes created, history read back |
| Own the schedule | none | 2-6 weeks | A review loop people will use twice |
The last row is the only one that is not a library-integration estimate, and the gap is the point of the table.
To Something Maintainable#
| Position | Additional work |
|---|---|
| Hand off | Stable model ids and note GUIDs; a real note type; media handling. 1-2 days. |
| Read | Almost none. The analysis is the work. |
| Drive | Error handling for every failure mode in S2’s table, most of which are indistinguishable at the connection layer. 1-2 days, and it is never finished, because the causes are outside your process. |
| Own the collection | Pinning against an unversioned API, and a license review. Days, plus a legal conversation. |
| Own the schedule | Queue builder, sync, import/export, backup, and an interface. Months. |
Where Estimates Go Wrong#
The queue builder. “Cards where due <= today” is five minutes and produces
a review experience people abandon. New-card throttling, daily caps, sibling
burying and learning steps are what make a session tolerable, and each is an
edge case in a query that looked trivial.
Media. In the hand-off position, media is the difference between an
afternoon and two days: files are renamed to integer indices inside the archive,
and a media JSON is the only record of their original names.
GUID design. Free if decided on day one. Extremely expensive after a deck has been distributed, because the correction orphans the review history of everyone who already imported it.
The license conversation. Not a development cost, and the one most likely to land after the code is written. If the product is served over a network and the official library is in scope, have it first.
Persona: The Content-Pipeline Maintainer#
Who: someone who already has the content — a vocabulary database, a generated set of morphological forms, an extracted glossary, a corpus with annotations — and needs it to arrive as reviewable cards.
Why this changes the answer: the content exists and is authoritative somewhere else. The cards are an output format, not a data store. Nothing about the review experience is theirs to design, and nothing that happens during review needs to come back.
The Constraint#
The pipeline is re-run. That is the whole shape of this persona: the corpus gets corrected, extended, re-annotated, and the deck is re-issued — repeatedly, possibly for years.
Which makes note GUIDs the only technically interesting decision in the entire integration. Derive the GUID from a stable key in the source data and each re-issue updates the reader’s existing cards while their review history survives. Let genanki derive it from field contents instead and every typo fix silently orphans a card, taking its history with it.
The failure is invisible from the pipeline side. The deck builds, the file is valid, and the damage is in someone else’s collection.
The Answer#
genanki. The hand-off position is not a compromise here — it is exactly correct. Delegating scheduling, sync, review UI and backup to an application the reader already trusts is the whole benefit, and the license imposes nothing.
Effort: hours for a first deck; a day or two for a re-issuable pipeline with stable ids, media, and a real note type.
What Would Flip It#
- If the corpus contained items that cannot be a front and a back — audio the reader must record, an interaction to perform — the format runs out and this becomes the product-builder persona.
- If the pipeline needed to know how the cards performed in order to decide what to generate next, the hand-off position cannot report back, and the answer becomes the official library or nothing.
Persona: The Educator#
Who: a teacher, course author, or training lead distributing material to a group who did not choose the tooling and will not troubleshoot it.
Why this changes the answer: every technical requirement here is dominated by one non-technical one — what can thirty people install without help?
The Constraint#
Adoption friction, counted step by step:
| Path | What the recipient must do |
|---|---|
.apkg file | Install one application, double-click a file |
| AnkiConnect | Install the application, install an add-on, keep it running |
| A hosted review tool | Make an account |
| Your own application | Trust you with their study data |
Each additional step removes people, and it removes them silently: nobody reports that they did not manage the install.
There is a second constraint that most technical comparisons miss: the recipients keep the cards afterwards. A course ends; the collection stays on the learner’s device, syncs to their phone, and remains useful for years. A hosted tool that expires with the course does not.
The Answer#
genanki, producing a plain .apkg. One application, one file, one
double-click, and the reader owns the result permanently.
Effort: hours. This persona rarely needs a pipeline — it needs one good deck, well-modelled, re-issued a few times a term.
The Detail That Matters Here#
Model design, more than tooling. A note type with recognition and recall templates from the same field pair doubles the review value of the same content for free, and a card that shows the reader an ambiguous prompt is worse than no card. This persona’s real work is in the templates, not in the integration.
What Would Flip It#
- Institutional policy forbidding the recipients from installing software. Then the answer is a hosted tool the institution already runs, and this category has nothing to offer.
- A requirement to see whether the class actually studied.
.apkgis one-directional; the deck goes out and nothing comes back. If completion has to be observed, the answer is a platform, not a file.
Persona: The Platform Integrator#
Who: a team adding spaced review to an existing hosted product — an LMS, a professional-training platform, a documentation site with practice built in.
Why this changes the answer: this is the persona the license boundary was written for, and it is the one most likely to discover it late.
The Constraint#
The product is served over a network. That single fact converts the category’s most capable library into its most expensive one.
AGPL-3.0-or-later carries a network clause: making the program available to
users over a network triggers the same source-provision obligation that
distributing a binary would. A service that imports anki in-process is the
case that clause exists to cover. There is no “we never shipped a binary”
argument available.
The mitigations, and where each one stands:
- Process isolation — run the AGPL code as a separate program behind a defined interface. Commonly done; whether it is sufficient is an unsettled legal question. This survey will not pretend to resolve it.
- Avoid the library entirely — the position most teams end up in, and the
reason
ankiserves fewer downloads than genanki despite being strictly more capable. - Ask a lawyer — the only advice a library survey can responsibly give, and the point of listing this persona is to make sure the question is asked before the code is written rather than after.
The Answer#
Own the schedule, using a scheduler from 1.141, with genanki as an export path. The combination gives the platform:
- no copyleft obligation in the serving process
- review history in its own schema, where the product can use it
- an exit for the customer, which is increasingly a procurement requirement rather than a nicety
Effort: weeks, with the same warning as the product builder — the queue builder, not the algorithm, is the hard part.
The Import Question#
Platforms in this position are often asked to ingest a prospect’s existing
collection, complete with history. That requires reading revlog, which
requires the official library, which is the license problem again — now in an
offline import job rather than in the serving path.
An offline batch importer, run as a separate process, is a much narrower
exposure than a hosted service linking the library. It is still a question to
ask first. It is also the only reason this persona might touch anki at all.
What Would Flip It#
If the platform is internal — an in-house training tool nobody outside the organization reaches — the network clause has nothing to attach to, and the official library becomes the obvious choice it was always going to be on capability alone.
Persona: The Power User#
Who: someone automating their own collection on their own machine — bulk edits, cards generated from their reading, a script that fixes a mistake across four thousand notes.
Why this changes the answer: every constraint that dominates the other personas is absent. There is one user, one device, no license exposure, and no adoption friction, because the person installing the add-on is the person who wrote the script.
The Constraint#
What is left when those fall away is immediacy. This persona is iterating against a collection they are actively using, and the loop matters more than the architecture. Export-modify-reimport is a five-step round trip; a local HTTP call is one line.
The Answer#
AnkiConnect, with the caveat that it is now an archived upstream
(2025-11-04) — read S2/ankiconnect.md before committing, and check the add-on
listing’s current state, which this survey could not verify.
It is the only option that reaches a live collection while its owner is using it, and this persona is the owner. The failure modes S2 lists — Anki must be running, a modal dialog blocks the API, errors arrive as English strings — are tolerable when the caller is sitting in front of the application.
Effort: minutes. The protocol is one endpoint and a JSON envelope.
The alternative: the official anki library, against a copy of the
collection with the application closed. Safer, and AGPL-irrelevant for personal
use, but it breaks the loop this persona is optimizing.
What Would Flip It#
The moment the script is shared. As soon as somebody else is meant to run it,
the add-on install becomes a support burden and the archived upstream becomes
someone else’s problem — and the answer moves to a .apkg they can import.
Persona: The Product Builder#
Who: a team building an application whose value is the reviewing — an adaptive practice tool, a certification trainer, a language product where the session design is the differentiator.
Why this changes the answer: nothing in this category can be handed the schedule, because the schedule is what is being sold.
The Constraint#
Two, and they pull the same way:
The interface is the product. Exporting a file for the reader to open in another application is not a lesser version of this product; it is a different product, and one the team cannot improve.
The review history is the asset. Retention curves, item difficulty, where people drop out — this is what informs the roadmap and, in many of these businesses, what the customer is paying for. It cannot live in a file on someone’s desktop.
The Answer#
None of these libraries. Take a scheduling algorithm from 1.141 — fsrs,
MIT, actively released — and own the card store, the review log, the queue
builder and the interface.
Effort: weeks, and S2’s warning applies. The scheduler is the small part; the queue builder is where estimates fail. New-card throttling, daily caps, sibling burying and learning steps are the difference between a review session people return to and one they abandon after three days.
The Exception Worth Building#
An export path, using genanki, at whatever point the product is mature enough to have churn. It costs a day and it removes “I would be trapped” from the objection list — and it is the same day’s work whether it is built early or under duress.
What Would Flip It#
If the team is validating demand rather than building the product, a genanki pipeline against the audience’s existing application answers “do people want these cards” in an afternoon, without building a review system at all. That is a research instrument, not a shipped product, and mistaking one for the other in either direction is expensive.
Persona: The Learning Researcher#
Who: someone studying how people actually learn — retention curves, item difficulty, the effect of a scheduling change — using collections that already exist.
Why this changes the answer: the question is about revlog, and only two
things in this category can read it.
The Constraint#
The data already exists and cannot be manufactured. A card can be regenerated from source; a year of somebody’s recall performance cannot. So this persona never writes, and the entire creation half of the category is irrelevant to them.
What they need is joins. The raw schema stores fields packed into a single
flds column, note types as JSON inside a one-row table, and reviews keyed by
card id with the timestamp encoded as the primary key. Every one of those is an
obstacle between the question and the answer.
The Answer#
ankipandas, and it is not a close call. col.revs.merge_cards() does the
join that would otherwise be the first afternoon of the project, and the result
is a DataFrame — which means every tool this persona already knows applies.
Effort: an hour to a first real answer.
Escalate to the official anki library only when the analysis has to write
something back, or when it needs collection state that ankipandas does not
expose. For an academic or internal analysis the AGPL asks nothing; this is the
persona for whom the license boundary does not reach.
The Trap#
Read-only is a feature. It would be easy to read this persona’s needs as “the same as everyone else’s, minus writing” and reach for a library that can do both. Writing to a collection database behind the application’s back, while it may be open, is how collections get corrupted — and this persona is working with data that is, by definition, irreplaceable.
What Would Flip It#
If the study requires controlling the schedule rather than observing it — an intervention arm with a modified algorithm — no library here helps. That is an instrumented build, using a scheduler from 1.141, and the existing collections become an import problem rather than a data source.
S3 Recommendation: Choose By Constraint, Not By Capability#
Across six personas, the technically strongest library — the official anki
package — is the right answer for exactly one of them, and only because that
persona is the one the license does not reach.
That is the finding. In this category the decision is forced by something outside the code.
The Table#
| Persona | Forcing constraint | Answer |
|---|---|---|
| Content-pipeline maintainer | Cards are an output format | genanki |
| Product builder | The review experience is the product | Own it (1.141) |
| Educator | What can thirty people install unaided? | genanki |
| Learning researcher | The question is about revlog | ankipandas |
| Power user | One user, one machine, tight loop | AnkiConnect |
| Platform integrator | Served over a network → AGPL | Own it, genanki for export |
The Two Rules That Cover Most Cases#
If the review experience is not part of what you are making, hand the schedule away. genanki, stable ids, done in a day. Every hard part of a review system — scheduling, sync, interface, backup, the reader’s trust — becomes someone else’s problem, and that is a bargain, not a compromise.
If it is, own the whole thing, and cost the queue builder rather than the algorithm. The scheduler is fifty to two hundred lines and there is a maintained package for it. What takes weeks is everything around it.
The Question to Ask First#
Does anything need to come back?
The hand-off position is one-directional by construction: revlog goes out
empty and the reader’s collection never reports in. If the answer is yes — the
pipeline needs to know what worked, the platform must ingest a prospect’s
history, the class’s completion has to be observed — then genanki is ruled out
before any other consideration, and the choice is between the official library’s
license and building your own.
Asking this on day one costs nothing. Discovering it in month four costs the integration.
What This Pass Does Not Do#
It does not pick for any particular product. Each persona above is a constraint with an answer attached; a reader whose constraints match one of them can take its answer, and a reader whose constraints span two will find that the positions compose — a platform that owns its schedule and exports with genanki is using two of them at once, correctly.
S4: Strategic
S4: Strategic Selection - Approach#
Research Date: 2026-08-25 Focus: What each position costs to leave, and what happens to the review history when you leave it
What This Pass Asks#
Not “which is best” but “what does this commit you to in three years”.
In this category that question has an unusually clean answer, because there is
exactly one thing worth protecting. Cards can be regenerated from source content
in an afternoon. Templates can be rewritten. Media can be re-encoded. Review
history cannot be reconstructed from anything. Every strategic question below
is a version of: what happens to revlog?
Method#
- Lock-in is scored per position, not per library, because the library is usually replaceable and the position is not. A program can swap genanki for a hand-written ZIP writer in a week; it cannot swap the hand-off position for the own-it position at all without rebuilding.
- Maintenance risk is measured from registry and repository state directly — release dates, last pushes, archive flags — checked on 2026-08-25 rather than inherited from the previous pass. Three of the previous pass’s facts had moved.
- Format longevity is assessed on the number of independent implementations, which for this format is one. That is treated as a risk to be stated, not as a reassurance.
What This Pass Will Not Do#
Forecast. The outlook section states what would have to happen for each scenario and what a reader should watch for, rather than assigning probabilities to a project whose roadmap is one team’s.
Exit Strategy#
Leaving Each Position#
Hand off → anything. Trivial. genanki holds no state; the source content is already yours. Replacing it means writing five tables into a zipped SQLite file. The decks already distributed keep working forever, because they are files in other people’s collections.
Read → anything. Equally trivial. ankipandas performs joins you could perform yourself. If it stopped working tomorrow, the analysis would resume after a day of SQL.
Drive → hand off. Moderate. The calling code changes shape — from a live API against a running application to a file the reader imports — and the reader bears the cost, because their workflow changes. This is the position whose exit cost lands on someone who did not choose it.
Own the collection → own the schedule. The one direction with real work but
no data loss. The official library can read revlog, so the history transfers
in full. Everything else is rebuilding the parts of the application you were
borrowing.
Own the schedule → anything. Expensive by construction, and the exit is not really yours — it is your users’. Which is exactly what the genanki export path is for.
The Direction That Loses Data#
Any collection → any non-Anki system, when the collection was scheduled by a modern algorithm.
From S4/lock-in.md: SM-2 state travels as structured columns; FSRS state
travels as an opaque string. An exporter reading cards.ivl and cards.factor
gets a faithful picture of an old collection and a defaulted, wrong picture of a
new one. The cards survive. The schedule does not.
Anyone who has told a customer “your data is portable” should check which scheduler produced it before repeating that.
The One-Day Insurance#
For anything in the own-it position: build the genanki export before you need it.
- It costs about a day.
- It drops the reader-facing lock-in score from 8 to about 3.
- It removes the strongest objection a prospect can raise.
- It is the same day’s work whether it is done in month two or during a churn conversation, except that in month two it is a feature and later it is a concession.
The export cannot carry review history out — no .apkg writer can, because
revlog is not something a generated deck has. Say that plainly rather than
implying otherwise; a portability claim that quietly excludes the only
irreplaceable data is worse than no claim.
Checklist#
- Is the
.apkgschema stored somewhere you control? - Are model ids and note GUIDs derived from stable source keys?
- If you own the schedule, does an export path exist and get tested?
- Do you know which scheduling algorithm your stored state assumes?
- If you depend on AnkiConnect, do you know its current listing state?
- If you link the official library, has the license question been asked by someone qualified to answer it?
Format Longevity: One Implementation, No Specification#
The Situation#
.apkg is the interchange format for this entire category. Every library here
either writes it, reads it, or drives an application that does.
It has one reference implementation and no specification. What the format
is, is whatever Anki reads. Third-party writers work by matching the schema the
application happens to accept — which is exactly how genanki was built, and why
S2/apkg-format.md had to be assembled by reading source code rather than by
citing a document.
Why It Has Been Stable Anyway#
- The core schema —
col,notes,cards,revlog,graves— has been recognizably the same for years. - Importers accept older layouts. A writer targeting the 2023-era format still produces files current Anki opens, which is why genanki’s three-year-old release is not a crisis.
- The application’s own exports have moved — newer collection members, different
compression, a separate
.colpkgextension for full-collection exports — but the import side has stayed permissive, and permissive importers are what third-party writers actually depend on.
Why That Is a Different Guarantee Than It Looks#
Stability by convention is not stability by contract. Nothing obliges the import path to stay permissive; it has stayed permissive because breaking it would break a large ecosystem, which is a strong incentive and not a promise.
The realistic failure is not a deliberate break. It is a schema addition that becomes load-bearing — a new column that new features depend on, which older writers do not populate, so their decks import but behave subtly wrong. That failure is quiet, it lands in the reader’s collection rather than in the producer’s build, and it is the class of problem an unmaintained writer does not get fixed for.
The cards.data column is the visible edge of this. It already carries modern
scheduling state as an unspecified string; anything that grows there is
invisible to every third-party tool.
What Would Change the Picture#
- A published specification. It would make third-party implementations durable rather than empirical. There is no sign of one, and no obvious incentive for the project to produce one.
- A second serious implementation with a real user base, which would make
the format a de-facto standard by having something to be compatible with.
Various apps import
.apkg; none of them defines it. - A general-purpose review-data interchange format, from outside this ecosystem. Nothing credible is in view.
None of these is close, so the posture to hold is: the format will keep working, and the reason it keeps working is one project’s continued good behavior rather than any guarantee you hold.
What to Do About It#
Hold the schema. It is short — five tables, listed in S2/apkg-format.md — and
the difference between “our writer broke” and “our writer broke and nobody here
knows what it was writing” is a page of SQL kept in the repository.
Lock-in by Position#
Scored 0-10 across five dimensions; totals are reported rather than averaged, so a single catastrophic dimension stays visible instead of being diluted.
| Dimension | What it measures |
|---|---|
| Format | How hard is the data to read without the incumbent? |
| History | Can review history be extracted, and does it survive extraction? |
| Code | How much of your program assumes this position? |
| Reader | What does the person reviewing have to do if you switch? |
| License | What obligations follow you out? |
Scores#
| Position | Format | History | Code | Reader | License | Total | Risk |
|---|---|---|---|---|---|---|---|
| Hand off (genanki) | 2 | 0 | 1 | 0 | 0 | 3 | Very low |
| Read (ankipandas) | 2 | 0 | 1 | 0 | 0 | 3 | Very low |
| Drive (AnkiConnect) | 3 | 2 | 3 | 6 | 0 | 14 | Moderate |
| Own the collection (anki) | 3 | 2 | 6 | 4 | 8 | 23 | High |
| Own the schedule (yours) | 7 | 7 | 9 | 8 | 0 | 31 | Highest — and chosen on purpose |
Reading the Table#
The hand-off position has almost no lock-in, because it holds almost
nothing. genanki writes a file and forgets. Replacing it means writing a ZIP
containing a SQLite database with five tables — a week’s work with the schema in
front of you, and the schema is in S2/apkg-format.md. Its History score is 0
in the sense that matters: there is no history to lose, because none was ever
collected.
The own-it position scores highest and that is not an argument against it.
Lock-in and ownership are the same thing seen from two sides. A team that builds
its own review system has committed to maintaining it, and the score simply says
so. What the score should prompt is the export path — genanki, one day’s work —
which drops Reader from 8 to about 3 and is the cheapest risk reduction
available anywhere in this table.
The official library’s 23 is almost all license. Strip the AGPL column and it scores 15, in the same band as driving a running collection. The lock-in is not technical; it is that the obligation follows the code into everything it is linked with, including things built later by people who were not in the original conversation.
The Asymmetry That Matters Most#
From S2/apkg-format.md: the interchange format carries SM-2 state as
structured columns — cards.ivl (interval) and cards.factor (easiness) —
and carries modern FSRS state as an opaque string in the free-form
cards.data column.
The consequence, stated plainly:
A collection scheduled by a 1988 algorithm is portable. A collection scheduled by a 2023 algorithm is portable only to implementations that agree on how to read a text column nothing specifies.
That is a lock-in finding that lives in a schema rather than in a license, and it will get worse rather than better: scheduler research keeps producing state that is richer than two integers, and the format’s structured columns were fixed around two integers decades ago.
Anyone whose exit plan is “we can always export” should check which scheduler their collections were built under before believing it.
Long-Term Outlook#
No probabilities. What follows is what would have to happen, and what to watch.
5 Years#
Most likely continuation. Anki remains the center of gravity; .apkg
remains the interchange format; genanki remains the default writer whether or
not it ships another release. The category stays small because it is solved
enough — writing cards is a job with a good answer, and there is little
commercial pull toward a second one.
What would change it
- Anki’s import path stops being permissive. The single event that breaks three unmaintained libraries at once. Watch the release notes for schema additions that new features depend on.
- genanki gets a maintainer, or a fork takes the download share. Either resolves the largest single-point-of-failure in the category. Watch PyPI: a new package climbing toward six figures of monthly downloads is the signal.
- AnkiConnect’s archive becomes a real break. Watch for the AnkiWeb listing changing state, and for a fork consolidating attention. Today the forks are small.
10 Years#
At this horizon the format question dominates the library question.
The scheduling-state problem gets worse before it gets better. Algorithms
keep producing richer state — FSRS tracks three quantities where SM-2 tracked
two, and successors will track more — while the interchange format’s structured
columns were fixed around two integers. Every generation of scheduler pushes
more meaning into the unspecified cards.data string, and every generation
makes collections less portable in the one dimension that matters.
The plausible resolutions:
- A specification emerges, from the project or from the wider spaced- repetition community, that gives scheduling state a real shape. This is the good outcome and nothing currently points to it.
- The center moves to hosted services, and interchange stops mattering because nobody holds a local collection. This is the outcome where the whole category quietly becomes irrelevant, and the review history ends up somewhere worse than a file on a laptop.
- Nothing changes.
.apkgremains a de-facto format defined by one implementation, tools keep matching it empirically, and portability keeps meaning “the cards, not the schedule”.
What a Reader Should Actually Watch#
Two things, both cheap to check:
- PyPI release dates for genanki and ankipandas. A release after three years of silence means something changed upstream that mattered.
- The
cards.datacolumn. If a future Anki gives scheduling state a real schema, portability in this category improves at a stroke — and if it does not, every claim about data portability keeps carrying an asterisk.
Maintenance Risk Across the Category#
All figures verified against PyPI and GitHub on 2026-08-25.
| Project | Last release | Repo last push | Status | Monthly downloads |
|---|---|---|---|---|
| genanki | 2023-11-12 | 2024-12-30 | Active repo, no releases | 269,751 |
| anki (official) | 2026-08-05 | 2026-08-25 | Fully active | 185,160 |
| ankipandas | 2023-10-11 | 2026-08-03 | Active repo, no releases | 275 |
| AnkiConnect | — | 2025-11-04 | Archived | 147 (client) |
The Pattern#
Three of the four third-party projects have not shipped a release in nearly three years, and one is archived. Only the official library — the one most teams rule out on license — is under active release.
The reassuring reading is that all of them still work, because the schema they target has not moved. The reading worth acting on is that the category’s stability is entirely downstream of one project’s stability. These libraries are not independently robust; they are targets sitting still because the thing they aim at is sitting still.
Reading Each One#
genanki — finished, not abandoned. Writing a stable file format is a job
that can be completed, and the repository was still receiving commits into late
2024. But 269,751 downloads a month are being served by a package with one
maintainer-shaped hole in it, and if the format ever moves, nobody is standing
there. The mitigation is not “find another library” — there isn’t one at this
scale. It is knowing the format well enough to fix it yourself, which is why
S2/apkg-format.md exists.
ankipandas — the same shape at 1/1000th the volume. Repository alive (pushed 2026-08-03), release stale (2023-10-11), 275 downloads a month. Low consequence: it is a read path, it holds nothing, and its function could be rewritten by its user in a day.
AnkiConnect — the one with a clock on it. Archived upstream, 2025-11-04. It is a compatibility shim between a caller and an application that ships roughly monthly; a shim that has stopped moving while its target has not is a liability even while it works. Forks exist and are small. This survey could not read the AnkiWeb listing (it requires JavaScript), so its catalog state is unverified here — anyone depending on it should check that themselves.
anki — the healthiest project and the least-chosen library. Released this month, 30k stars, continuously developed. Its risks are the opposite kind: no API stability contract, and a license with a network clause.
The Risk Nobody Prices#
The failure mode for this category is not a library going unmaintained. It is Anki changing something and three unmaintained libraries all needing a fix at once. They share a single point of failure, and the diversification a reader might imagine they have — four packages, four maintainers — is not real.
The practical hedge is unglamorous and cheap: pin versions, keep a copy of the
.apkg schema (it is short), and treat the ability to read and write the format
directly as a capability worth having rather than as an emergency measure.
S4 Recommendation: What the Long View Changes#
It Does Not Change the Default#
genanki remains the answer for the common case, and S4 strengthens rather than weakens that: the hand-off position scores lowest on lock-in in the whole category, because it holds nothing. A library that writes a file and forgets is a library you can replace in a week.
The three-year release gap that looks alarming on a maintenance dashboard turns out to be the least consequential risk here, and the reason is: the exposure is the format, not the package. Every third-party tool in this category shares it, so switching libraries does not reduce it. Knowing the format does.
The Three Strategic Facts#
1. Review history is the only irreplaceable thing, and the hand-off position never collects it. That is a correct trade for most programs and a fatal one for a few. Decide it on day one, because it is not revisitable later — there is no history to go back for.
2. Portability is scheduler-dependent. SM-2 state is structured and travels; modern FSRS state is an opaque string in a column nothing specifies. Any “your data is portable” claim needs to name which half it means.
3. The category has one point of failure, not four. Three unmaintained libraries and one archived add-on all work for the same reason: Anki’s import path has stayed permissive. That is a strong convention, not a contract, and it is shared — the apparent diversification is not real.
The Cheapest Risk Reductions Available#
In order of return per day spent:
- Store the
.apkgschema in your own repository. An hour. It is five tables. It converts “our writer broke and nobody knows what it was writing” into an afternoon’s fix. - Derive model ids and note GUIDs from stable source keys. Free on day one, very expensive after distribution, and the only mistake in this category that destroys something a reader cannot recover.
- If you own the schedule, ship the genanki export before you need it. One day. Drops reader-facing lock-in from 8 to about 3 and turns a churn concession into a feature.
- Ask the license question before writing code, if the product is served over a network and the official library is in scope.
By Position#
| Position | Strategic verdict |
|---|---|
| Hand off (genanki) | Safe. Lowest lock-in in the category. Know the format; keep the schema. |
| Read (ankipandas) | Safe. Holds nothing; replaceable in a day. |
| Drive (AnkiConnect) | Time-boxed. Works today, archived upstream, exit cost lands on the reader. Fine for personal automation; a poor foundation for anything shipped. |
| Own the collection (anki) | Capable, license-bound. The only path to review history. The obligation follows the code into everything linked with it, including things built later. |
| Own the schedule | Highest lock-in, chosen on purpose. Correct when the review experience is the product. Add the export path early. |
The One-Sentence Version#
Hand the schedule away unless the review experience is what you are selling, and in either case know what is inside the file — because in this category the format is the dependency, and the libraries are just the current way of reaching it.