Getting Started

django-resume is a Django app that provides a simple way to create a resume within your Django website. It is designed to be easy to use and customize. You can write plugins to extend the functionality of your resume.

Custom plugins are added as Python code plus template files in your Django project. django-resume no longer supports database-backed plugins.

Plugins

This is the list of built-in plugins that come with django-resume:

  • About: A simple about section.

  • Cover: A cover page with some textual information and profile picture.

  • Education: Just the name of the school and the time you attended.

  • Identity: Your name, email, phone number, profile picture and social media links.

  • Permission Denied: The page that is shown when you try to access a part of the resume you need a token for.

  • Projects: A list of projects you have worked on.

  • Skills: A list of skills you have.

  • Page Theme: The django-resume theme used for built-in pages, editing UI, cover letters, and plugin templates (for example plain or headwind).

  • Timeline: A timeline of your work experience.

  • Tokens: A token that you can use to access parts of the resume that are protected.

Text Formatting

Some built-in plugins render a small, sanitized markdown subset for user-provided text fields. This currently applies to text-heavy sections such as About, Cover, Projects, Timeline, and Permission Denied.

The supported formatting is intentionally limited to:

  • headings

  • bold

  • italic

  • links

  • line breaks

Rendered HTML is sanitized before it is marked safe, so raw HTML is not preserved and dangerous link protocols are removed.

Exporting to JSON Resume

Export a resume to the JSON Resume interchange format with:

python manage.py export_json_resume <slug> [--output FILE]

The document is written to stdout (or --output FILE); an export report – mapped plugins, omitted plugins, dropped fields, and any omitted invalid dates – is written to stderr. The command exits non-zero if the document fails validation against the pinned JSON Resume v1.0.0 schema and writes no output. Authenticated owners can also download the same export from /<resume-prefix>/<slug>/json-resume/. The URL returns application/json with an attachment filename of <slug>.json and is deliberately owner-only, even if the public CV is tokenless.

Exports include a meta.django_resume extension envelope with django-resume plugin data needed for exact same-application round trips. Standard JSON Resume fields remain schema-valid; django-resume-only values such as display dates that do not match JSON Resume’s date pattern stay in the extension envelope instead of being forced into portable fields. Treat django-resume exports as private backup or migration files, not public registry uploads: the meta.django_resume.plugin_data envelope contains application-private plugin data, including access-control plugin settings such as CV tokens when those are present. Remove the meta.django_resume envelope before sharing an export with third-party JSON Resume hosting or tooling that does not need same-application restoration.

Rendering with JSON Resume Render Themes

django-resume has two different theme concepts:

  • A page theme is a Django template set used by django-resume pages and plugins. It affects the cover page, CV page, editing UI, and cover-letter content rendered by django-resume itself.

  • A JSON Resume render theme is an npm package from the JSON Resume ecosystem. It receives an exported JSON Resume document and returns a separate HTML rendering of that document.

Authenticated resume owners can choose from a curated JSON Resume render theme catalog at /<resume-prefix>/<slug>/json-resume/themes/. The catalog is deployment owned: each entry has a stable local key, an npm package name, and an exact pinned version. The default page shows catalog cards with preview images, package/version metadata, a local filter, a Preview render action, and a separate Use render theme action. For example, the local example server can open the Smaugustus Emberflame theme catalog at http://localhost:8000/resume/smaugustus-emberflame/json-resume/themes/. Catalog images and public registry demos are illustrative only: the JSON Resume registry may render different resume data or a different package version than the deployment-pinned catalog entry. Use Preview render to see the actual local output for the current resume and pinned package.

Preview render opens a private rendered HTML page for that catalog theme without changing Resume.integration_data. Use render theme runs npm install for the pinned catalog package and stores the selected catalog key under Resume.integration_data["json_resume"]["theme"]. Existing resumes that stored a selected theme as {"package": "jsonresume-theme-..."} continue to render through that legacy package state.

Once a JSON Resume render theme is selected, owners can open /<resume-prefix>/<slug>/json-resume/rendered/ to view the resume rendered through that theme. This does not replace the normal /<slug>/cv/ page. The normal CV route continues to use the resume’s page theme; the JSON Resume route is a separate export/render artifact. The renderer receives a portable JSON Resume projection: django-resume removes its private meta.django_resume envelope before writing the temporary resume.json passed to the Node renderer.

Developers and site operators can also render a static HTML file outside django-resume with the JSON Resume command-line tooling. First export the resume:

python manage.py export_json_resume <slug> --output resume.django-resume.json

Then install resumed and the theme package in a local npm project and render the file:

npm install resumed jsonresume-theme-even
npx resumed render resume.django-resume.json --theme jsonresume-theme-even --output resume.html

This is useful for private local output, CI artifacts, or publishing a static HTML file through a separate deployment process. The exported JSON contains django-resume’s private meta.django_resume envelope, so strip it before giving the file to third-party hosting, registry uploads, or any theme package you do not fully trust:

jq 'del(.meta.django_resume) | if .meta == {} then del(.meta) else . end' \
  resume.django-resume.json > resume.json
npx resumed render resume.json --theme jsonresume-theme-even --output resume.html

The command-line renderer is separate from the in-app preview. It uses whichever resumed and theme package versions are installed in that npm project, while the django-resume owner UI uses the deployment-pinned catalog and local theme cache.

Theme packages execute JavaScript during rendering. Only authenticated owners can preview, select, or render themes through these views, but catalog packages should still be treated as trusted local code chosen by the site operator. Preview and Use render theme may run npm install for the pinned catalog package into django-resume’s configured local theme cache. Rendering itself uses the local cache and does not fetch schemas, renderers, or themes from the network. django-resume does not install themes for anonymous visitors, and public CV pages or token-protected CV links do not imply permission to install or render JSON Resume themes.

Rendered theme responses use a restrictive Content Security Policy by default: inline styles are allowed for theme CSS, but browser-executed theme scripts and remote stylesheet links are blocked. Operators who trust their curated render themes and need browser-side theme JavaScript, such as date-duration custom elements emitted by some themes, can set DJANGO_RESUME_JSON_RESUME_ALLOW_THEME_SCRIPTS = True. That opt-in also allows Google Fonts stylesheet links while keeping external scripts blocked. Because inline theme scripts can still read the rendered page and trigger allowed image requests, enabling this setting means trusting curated themes with the rendered resume data.

Arbitrary npm theme search and install is disabled by default. Operators can set DJANGO_RESUME_JSON_RESUME_ALLOW_DYNAMIC_THEME_INSTALL = True to show the old npm search/install UI as a visibly separate development-discovery section. That mode lets resume owners install packages named like jsonresume-theme-* or @jsonresume/jsonresume-theme-* from npm, so it should not be enabled for production deployments unless owner-triggered third-party JavaScript execution is an accepted risk.

Importing from JSON Resume

Authenticated owners can import a JSON Resume file from the resume overview. The import form creates a new resume owned by the current user from either an uploaded resume.json file or an HTTP(S) JSON Resume URL, plus a caller-supplied slug. Provide exactly one source. URL imports are limited to public-address http or https URLs and use the same input-size limit as file uploads. The optional name field overrides basics.name; when neither is present, django-resume uses the slug as the resume name.

The browser import matches the management command’s create-only behavior. It validates the incoming document against the pinned JSON Resume v1.0.0 schema, rejects duplicate JSON object keys, requires a globally unique slug, and reports mapped, restored, omitted, or lossy plugin data after a successful import. By default, a django-resume round-trip export restores meta.django_resume.plugin_data so application-private fields can survive a backup or migration. Select Standard JSON Resume fields only to ignore that private envelope and import only standard JSON Resume fields through plugin adapters.

Signed provenance and update-in-place imports remain future work in the JSON Resume plan. Browser import currently creates a fresh resume; it does not merge or replace data in an existing resume.