CLI tool
jupyter/nbgrader avatar
jupyter/nbgrader

nbgrader for Assigning and Grading Jupyter Notebooks

A system for assigning and grading notebooks

1,374 stars343 forksPythonBSD-3-Clause

At a glance

What is it?
nbgrader is a Python and Jupyter system for creating notebook assignments, releasing them to students, collecting submissions, and combining automated grading with instructor review. It is best suited to courses where notebook work is part of the assessment workflow.
Who is it for?
Adopt nbgrader when assignments and submissions are Jupyter notebooks and instructors need a workflow that includes both automated checks and manual review. Do not choose it as a standalone grading engine for question types outside its notebook-oriented workflow without first checking the documented support.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What nbgrader Changes in a Notebook Course

nbgrader addresses the operational work that appears when a course uses Jupyter notebooks as graded assignments. An instructor needs to create an assignment, decide what students receive, collect completed notebooks, run checks against submissions, and still inspect work that cannot be judged by an automatic test. nbgrader groups those tasks into a system rather than treating assignment distribution and grading as unrelated file exchanges.

The project is aimed primarily at instructors and students in the Jupyter ecosystem. The README describes an instructor toolbar extension, a formgrader extension, a student assignment list, and command line tools. These interfaces address different parts of the same workflow. The toolbar and formgrader support instructor actions, while the assignment list gives students a place to view, fetch, submit, and validate assignments. The command line tools provide a separate route for course automation or administrative workflows.

Its scope is notebook-centered rather than a general-purpose examination platform. The repository metadata describes the project as “A system for assigning and grading notebooks,” and the Python package metadata identifies Jupyter, JupyterLab, and notebook grading as its purposes. That distinction matters for adoption. A course that already accepts arbitrary files, uses a separate assessment platform, or grades only handwritten submissions will need to check whether nbgrader's notebook model matches its workflow.

The Assignment, Submission, and Grading Cycle

The documented mechanism is a cycle with two main forms of grading. In the first part of the cycle, an instructor creates an assignment and generates the student version. The README specifically identifies generating the student version, releasing assignments to students, collecting assignments, autograding submissions, and manually grading submissions as core formgrader operations.

After students work in Jupyter notebooks, they can use the student assignment list to locate an assignment, fetch it, submit it, and validate the submission. This gives students a defined path for handling assignment files rather than leaving the process at an informal collection step. The README does not document the internal transport or storage format, so the repository does not establish whether a particular deployment uses a web server, filesystem storage, or another backend.

For instructors, the formgrader combines automated and human review. Automatic grading is appropriate for checks represented by notebook assertions or other supported notebook mechanisms, while manual grading remains necessary for responses that require interpretation. The documented architecture therefore does not remove the instructor from grading. It places automated checks and instructor review in one workflow.

The command line tools offer an alternative interface to the same major operations: generate, assign, release, collect, and grade notebooks. That is useful when an instructor wants repeatable administrative steps rather than clicking through notebook controls. However, the README does not give the command syntax, directory conventions, or deployment configuration, so those details must come from the linked command line documentation.

Jupyter Extensions and Python Package Boundaries

nbgrader is not only a Python library. The repository contains a `@jupyter/nbgrader` Node package for the frontend side of the extensions, while the `pyproject.toml` declares the Python distribution. The Python metadata requires Python 3.11 or newer and includes dependencies for JupyterLab 4, Notebook 7, `nbclient`, `nbconvert`, `jupyter_server`, `ipywidgets`, `sqlalchemy`, and related notebook infrastructure.

The version boundaries are concrete. `jupyterlab` is declared as `>=4.2.0,<5`, and `notebook` is declared as `>=7.2.0,<8`. The package also requires `jupyter_client<9`, `sqlalchemy>=1.4,<3`, `nbconvert>=6`, and `nbclient>=0.6.1`. These constraints make nbgrader part of a specific Jupyter generation rather than a package that can be installed independently of its surrounding runtime.

The repository layout shows both `nbgrader/` and `src/`, alongside `package.json`, `yarn.lock`, `tsconfig.json`, and Jupyter builder configuration. The package scripts include `jlpm build:lib`, `jupyter-builder build .`, and `jlpm build:labextension:dev`. Those entries are development and build procedures, not installation instructions for end users. The README instead directs users to the Installation section of the User Guide for detailed setup of nbgrader and its Jupyter notebook extensions.

This distinction prevents a common mistake. Installing the Python distribution may be only one part of making the extensions available in the intended Jupyter environment. The documentation's separate treatment of Python and notebook extensions is a reason to verify the complete installation path before deciding that the system is ready for a course.

Installation and the First Course Workflow

The README does not publish an exact installation command. It points to the Installation section in the nbgrader User Guide, so the first deployment step should be to follow that documentation for the target Jupyter environment. The repository metadata does confirm the relevant runtime requirements, including Python 3.11 or newer and JupyterLab 4.2 or newer within the declared `<5` range.

A first real use can be planned without inventing command flags. After installing the package and enabling the documented extensions, an instructor can create a notebook assignment through the instructor toolbar. The formgrader can then generate the student version and release the assignment. Students open it in the Jupyter notebook interface, use the student assignment list to fetch and validate the assignment, complete the notebook, and submit the result.

For grading, the instructor returns to formgrader or uses the documented command line tools to collect submissions and run autograding. The remaining review is manual grading. This is the first useful workflow to verify because it touches all four documented roles: assignment creation, student submission, automated checking, and instructor review. A course can then test whether the generated student notebook contains the intended cells and whether its grading cells behave as expected.

The repository does not state a default server port, environment variable, database URL, or deployment command. It also does not provide enough command syntax to reproduce a complete terminal tutorial. Those omissions are significant for administrators. Installation should not be treated as complete until the documentation has been checked against the actual Jupyter Server, Notebook, JupyterLab, and course storage arrangement.

Automated Checks Still Need Instructor Judgement

The clearest limitation is that notebook automation cannot replace grading judgment. nbgrader explicitly supports both autograding and manual grading, which indicates that the project expects some submissions to require human evaluation. A notebook cell can contain code, prose, charts, or an explanation whose quality is not equivalent to a pass or fail assertion. Instructors still need to define the rubric and review the relevant output.

There is also a deployment constraint. The package depends on JupyterLab and Notebook versions in major-version ranges, and its frontend uses Jupyter builder and TypeScript assets. A course running an older Jupyter stack may find that the declared Python or JavaScript dependencies do not match its environment. The repository supports JupyterLab 4.2 or newer, so an older course environment needs migration work or a separate compatible path before adoption.

The README does not document rollback, database migration policy, grading export formats, authentication behavior, or a documented service-level recovery process. Those are not claims that the project lacks them. They are documentation gaps that matter to an administrator planning production use. An instructor would need answers to those questions in the linked documentation or the project's operational setup.

For a course whose grading is entirely deterministic, automated checks may be sufficient. For open-ended work, the cost of adoption includes writing checks, reviewing exceptions, and configuring the course environment. That is a different cost profile from simply uploading submissions to a form.

nbgrader Compared with a Separate Assessment Platform

nbgrader's practical alternative is a separate assessment or submission platform that accepts files and stores grades outside the notebook environment. The difference is not merely branding. nbgrader keeps the assignment lifecycle close to Jupyter notebooks, with student-side extensions and instructor-side notebook grading controls built around notebook operations. A general submission form usually handles file upload and grade records but does not inherently provide notebook generation, notebook-aware autograding, or an in-notebook grading interface.

The trade-off is control versus scope. A dedicated nbgrader deployment gives instructors notebook-specific workflow components, including the formgrader and assignment list. In exchange, the course must operate within the package's Jupyter, Python, dependency, extension, and storage requirements. A separate assessment platform may be a better fit when assignments include many non-notebook formats, grading policies are administered outside Jupyter, or instructors do not want to manage notebook extensions.

The README does not claim compatibility with a particular commercial or institutional platform, and it does not describe migration tools for grades or assignments. The correct comparison therefore depends on the course's file types and deployment constraints. nbgrader is appropriate when the notebook is the unit of work and when instructors need both machine checks and manual review. It is less direct when the notebook is merely one file type among many.

License, Releases, and Maintenance Boundaries

The project uses the BSD-3-Clause license, as shown in both the repository metadata and the LICENSE reference in `pyproject.toml`. The package metadata identifies the Jupyter Development Team as the author. This information describes the declared licensing terms and attribution information, but it is not legal advice about a particular deployment.

The current repository version is 0.9.6 in `pyproject.toml` and `package.json`. The release list records v0.9.6 on 2026-09-30, v0.9.5 on 2025-01-17, and v0.9.4 on 2024-11-18. The repository is not archived. Its last push was on 2026-10-14, so the available maintenance record shows recent repository activity, although release cadence is not identical to ongoing compatibility for every Jupyter environment.

Upgrade cost depends on the declared version ranges and the installation format. The Python package uses Hatchling and `jupyter-builder` as build requirements, while the frontend uses `jlpm` scripts and a `yarn.lock`. A course adopting nbgrader should therefore test both Python dependencies and notebook extension assets when changing versions. The repository does not document an automatic migration path for course databases or assignment metadata, so the existence of `alembic` as a dependency should not be treated as proof that upgrades are automatic.

Editorial conclusion

Adopt nbgrader when assignments and submissions are Jupyter notebooks and instructors need a workflow that includes both automated checks and manual review. Do not choose it as a standalone grading engine for question types outside its notebook-oriented workflow without first checking the documented support. Verify installation, extension behavior, submission storage, and your course's grading model before deployment. The project is not archived, and the last push was on 2026-10-14.

Frequently asked questions

What is nbgrader used for?

nbgrader is used to create and assign Jupyter notebook work, release assignments to students, collect submissions, autograde notebooks, and manually grade remaining work. It targets courses built around the Jupyter notebook interface.

How do I install nbgrader?

The README directs users to the Installation section of the nbgrader User Guide. It does not include the exact installation command, so no command can be confirmed from the README alone.

Does nbgrader support JupyterLab 4?

Yes. The Python metadata declares `jupyterlab>=4.2.0,<5` and `notebook>=7.2.0,<8`, along with Python `>=3.11`. The repository also includes Jupyter frontend build and extension files.

Official sources

  1. jupyter/nbgrader on GitHub
  2. License: BSD-3-Clause
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jupyter-nbgrader.svg)](https://hysenlabs.com/projects/jupyter-nbgrader)

Was this useful?