Framework
tfranzel/drf-spectacular avatar
tfranzel/drf-spectacular

drf-spectacular: OpenAPI 3 schema generation for Django REST Framework

Sane and flexible OpenAPI 3 schema generation for Django REST framework.

2,862 stars337 forksPythonBSD-3-Clause

At a glance

What is it?
drf-spectacular replaces DRF's built-in schema generator with one that models serializers as reusable components and lets you correct the output through @extend_schema. It stays below 1.0 on purpose, so pin the version and diff the schema on every upgrade.
Who is it for?
Adopt drf-spectacular if you run a DRF API that other teams or generated clients consume, and you are willing to annotate the views the introspection cannot resolve. Do not adopt it if you need a stable schema contract across upgrades without reviewing a diff each time, or if your API is small enough that a hand-written OpenAPI file is less work.
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 28 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 September 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What drf-spectacular adds over the schema generator inside DRF

Django REST Framework ships with an OpenAPI generator, and drf-spectacular is a heavily modified fork of it. The README is blunt about why the fork exists: the upstream generator was lacking the features listed below it. The most consequential of those is that serializers become components in the OpenAPI document rather than being inlined at every use site. That matters as soon as a serializer is nested or recursive, because inlining a recursive structure either fails or produces a document that client generators cannot process. Components give the nesting a name and a single definition.

The second addition is a correction layer. Introspection over DRF views cannot know that a particular endpoint accepts a query parameter that no filter class declares, or that a POST returns 201 with a different serializer than the one on the view. The @extend_schema decorator is the documented answer: it attaches additional parameters, overrides request and response serializers per status code, and handles polymorphic responses either through the PolymorphicProxySerializer helper or through rest_polymorphic's PolymorphicSerializer.

The intended audience is a Django team that already has a DRF API and now needs a machine-readable description of it, either for external consumers or for client code generation. The README states the third goal directly: generate a schema that works well with the most popular client generators. If nobody consumes the schema, the annotations are work with no payoff.

How schema extraction works, from view to components

The entry point is a custom AutoSchema class. Registering it as DEFAULT_SCHEMA_CLASS makes DRF route schema generation through drf-spectacular instead of its own class. From there the generator walks the registered views and their serializers, derives paths and operations, and emits an OpenAPI 3.0.3, 3.1 or 3.2 document depending on the OAS_VERSION setting. Version 3.1 support is opt-in through that setting rather than the default.

Several extraction behaviours are worth knowing before you read your first output. operation_id values are derived from the path, which the README describes as sane naming; the practical effect is that two views on similar paths can collide and need an explicit override. Tags are extracted rather than declared, so the grouping in Swagger UI follows what the generator inferred. Descriptions come from docstrings. SerializerMethodField types are not knowable from the field itself, so they require either a type hint or the @extend_schema_field decorator. These are the places where the generated document will be wrong or empty on the first run, and they are exactly the places the annotation layer exists to fix.

Authentication is handled for DRF's native classes and is described as easily extendable. The README also lists first-class support for a set of third-party packages, including SimpleJWT, DjangoOAuthToolkit, django-filter, drf-nested-routers, djangorestframework-camel-case, djangorestframework-gis, Pydantic 2.0 and newer, django-rest-knox, and the django-polymorphic pair. Support here means the generator recognizes those libraries' constructs instead of producing an empty or misleading schema for them.

Installing drf-spectacular and generating your first schema.yml

Installation is a pip install, one entry in INSTALLED_APPS, and one setting. The README gives these three steps in that order. Note that the app label uses an underscore while the distribution name uses a hyphen.

bash
pip install drf-spectacular

Then add the app and point DRF at the AutoSchema class in settings.py. Without the DEFAULT_SCHEMA_CLASS line, DRF keeps using its own generator and the annotations below have no effect.

python
INSTALLED_APPS = [
    # ALL YOUR APPS
    'drf_spectacular',
]

REST_FRAMEWORK = {
    # YOUR SETTINGS
    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}

The README states that no settings are strictly necessary because the defaults work reasonably well, but recommends at least the metadata block. SERVE_INCLUDE_SCHEMA controls whether the schema endpoint itself appears in the document.

python
SPECTACULAR_SETTINGS = {
    'TITLE': 'Your Project API',
    'DESCRIPTION': 'Your project description',
    'VERSION': '1.0.0',
    'SERVE_INCLUDE_SCHEMA': False,
}

The first real use is the management command. It writes the schema to a file, and the --validate flag checks the result. The README's own example pipes that file into a Swagger UI container on port 8080.

bash
./manage.py spectacular --color --file schema.yml

Two things to check in schema.yml before you go further. First, that paths you expected are present at all; a view whose serializer the generator cannot resolve tends to appear with an empty or missing request body rather than an error. Second, that components.schemas contains your serializers with the names you expect. If a serializer is missing there, it was inlined, which usually means a recursive or nested structure the generator could not model.

Environments without internet access and the sidecar package

The default UI views fetch Swagger UI and Redoc assets from CDNs. In an air-gapped or egress-restricted deployment those fetches fail and the documentation page renders blank. drf-spectacular-sidecar is the documented answer: it ships the same static files as a separate optional package so Django's collectstatic can pick them up locally.

bash
pip install drf-spectacular[sidecar]

The sidecar app must be in INSTALLED_APPS for collectstatic discovery, and three settings switch the asset sources. The README describes SIDECAR as a shorthand. Note that the extra is named sidecar in the README's install line while the metadata also lists an offline extra.

python
INSTALLED_APPS = [
    'drf_spectacular',
    'drf_spectacular_sidecar',
]
SPECTACULAR_SETTINGS = {
    'SWAGGER_UI_DIST': 'SIDECAR',
    'SWAGGER_UI_FAVICON_HREF': 'SIDECAR',
    'REDOC_DIST': 'SIDECAR',
}

This is a packaging decision with a cost: you now carry the UI assets in your own static pipeline and update them when the sidecar package updates, instead of inheriting whatever the CDN serves.

The pre-1.0 versioning policy is the real constraint

The README states that drf-spectacular deliberately stays below version 1.x.x to signal that every new version may potentially break you, and recommends pinning the version and inspecting a schema diff on update. That is not boilerplate caution; it is the project's own description of its contract, and it should shape how you adopt it.

The versioning semantics are split by stream. A y-stream increment may contain breaking changes to both the Python API and the generated schema. A z-stream increment will not break the API and may only contain schema changes that the project judges unlikely to break you. The word unlikely is doing real work there: a schema change that is harmless to one consumer can break a client generator or a contract test elsewhere.

This creates a specific failure mode that has nothing to do with bugs. You upgrade a dependency for an unrelated reason, the resolved drf-spectacular version moves, and the generated schema changes shape. Nothing raises an exception. Your published API documentation and any generated clients silently drift from what the server actually does. Teams that treat the schema as a build artifact with a committed diff catch this. Teams that generate it on demand during deployment do not.

The same policy cuts the other way for a different audience. If you need a schema you can freeze for years without review, this project's own documentation tells you it will not give you that. The trade is deliberate: the maintainer prefers the freedom to correct extraction behaviour over a compatibility promise.

drf-spectacular and drf-yasg solve the same problem differently

The obvious comparison is drf-yasg. Both turn a DRF API into a machine-readable schema and both serve a browsable UI. The difference is the target specification and the extraction strategy.

drf-spectacular generates OpenAPI 3.0.3, 3.1 and 3.2, with the 3.1 and 3.2 document versions selected through the OAS_VERSION setting. drf-yasg is associated with Swagger 2.0 and OpenAPI 3 in the searches people run, but the meaningful distinction for a new project is that OpenAPI 3.1 aligns the schema dialect with JSON Schema, which changes how nullable types, exclusive bounds and similar constructs are expressed. If your client generators or gateway expect a 3.1 document, that is a reason to pick drf-spectacular.

The second difference is how much correction the tool expects from you. drf-spectacular leans on introspection first and gives you @extend_schema when introspection is wrong or incomplete. That is a good fit for a codebase that is mostly standard DRF viewsets and serializers, where the generator gets most of the document right and you annotate the exceptions. It is a poor fit for an API built on custom view classes, hand-rolled request parsing, or serializers the generator cannot resolve, because then the annotation layer becomes the document and you are writing OpenAPI with Python decorators.

Neither tool removes the work of deciding what your API contract actually is. They differ in whether you express that decision as annotations on code or as a schema file you maintain.

Licence, dependencies and upgrade cost

drf-spectacular is licensed under BSD-3-Clause, and the package metadata declares the same identifier. That is a permissive licence, but the usual caveat applies: the licence covers this project, not the dependency tree you assemble around it, and nothing here is legal advice. If you redistribute the sidecar's static assets, check their own terms separately from drf-spectacular's.

Runtime dependencies are Django, djangorestframework, uritemplate, PyYAML, jsonschema, inflection, and typing-extensions on Python below 3.10. The README states Python 3.8 or newer, Django 3.2 through 6.0, and DRF 3.12 through 3.17. The metadata's classifier list is broader than the README's requirements section, including Django 2.2 and older Python versions, so trust the requirements section and your own environment rather than the classifiers when deciding whether an upgrade is safe.

The upgrade cost is the versioning policy plus the schema diff. Practically, that means pinning the version, keeping the generated schema in version control, and reviewing the diff as part of the dependency bump rather than after it. The project publishes a CHANGELOG.rst at the repository root, which is where the schema-affecting changes are described. The last push to the repository was on 2026-09-02, and the most recent release listed is 0.30.0 from 2026-07-06.

Editorial conclusion

Adopt drf-spectacular if you run a DRF API that other teams or generated clients consume, and you are willing to annotate the views the introspection cannot resolve. Do not adopt it if you need a stable schema contract across upgrades without reviewing a diff each time, or if your API is small enough that a hand-written OpenAPI file is less work. Before committing, verify three things: that every view you care about produces the parameters and request bodies you expect, that the version you install matches the Django and DRF versions in your environment, and that a schema diff between your current pinned version and the next one is empty or explainable. The project itself tells you to treat every new version as potentially breaking, so the diff is not optional tooling, it is part of the upgrade.

Frequently asked questions

What is drf-spectacular?

It is an OpenAPI 3 schema generator for Django REST Framework, described in its README as a heavily modified fork of DRF's own OpenAPI generator. It extracts schema information from DRF and provides an annotation layer for correcting what introspection gets wrong.

How do I install drf-spectacular?

Install it with pip install drf-spectacular, add 'drf_spectacular' to INSTALLED_APPS, and set DEFAULT_SCHEMA_CLASS to 'drf_spectacular.openapi.AutoSchema' in your REST_FRAMEWORK settings. The README recommends also setting at least TITLE, DESCRIPTION and VERSION in SPECTACULAR_SETTINGS.

How do I use drf-spectacular to generate a schema file?

Run the management command ./manage.py spectacular --color --file schema.yml to write the schema to a file. Adding the --validate flag also validates the generated schema, according to the README.

What is drf-spectacular-sidecar for?

It provides the Swagger UI and Redoc static files as a separate optional package for environments that cannot reach CDNs. Install it with pip install drf-spectacular[sidecar], add drf_spectacular_sidecar to INSTALLED_APPS, and set SWAGGER_UI_DIST, SWAGGER_UI_FAVICON_HREF and REDOC_DIST to SIDECAR.

How does drf-spectacular compare with drf-yasg?

The README positions drf-spectacular around OpenAPI 3.0.3, 3.1 and 3.2 output, with the 3.1 and 3.2 document versions selected through the OAS_VERSION setting. drf-yasg is the other generator people commonly compare it against; the README does not discuss it directly, so any claim about its output should be checked against drf-yasg's own documentation.

Official sources

  1. License: BSD-3-Clause
  2. Project website
  3. README
  4. Releases
  5. tfranzel/drf-spectacular on GitHub
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/tfranzel-drf-spectacular.svg)](https://hysenlabs.com/projects/tfranzel-drf-spectacular)