Resume Toolkit - JSONresume/BibTeX to HTML/PDF
6.1K
resume-toolkit allows you to produce beautiful HTML and PDF versions from your JSON Resume (and optionally, BibTeX) files.
[!TIP] Examples:
You can see a live real example at https://zzamboni.org/vita/.
You can find some further samples in the
samples/directory:
samples/example-resume/: fully synthetic example which shows a variety of features.samples/john-doe-brilliantcv/: the sample resume from Brilliant-CV (the one produced when you runtypst init @preview/brilliant-cv) converted to JSONresume format, to show the Typst rendering abilities (the resulting PDF is nearly identical).
Convert from JSON Resume and BibTeX files into:
Additional functionality:

flowchart TD
A[JSON Resume<br/>resume.json] --> C[resume-toolkit]
B["BibTeX files<br/>publications.bib ...<br/>(optional)"] .-> C
C -. update-* commands .-> A
subgraph CV[CV outputs]
D[HTML<br/>vita/index.html]
E[PDF<br/>vita/resume.pdf]
end
subgraph PUBS[Publications outputs]
F[HTML<br/>vita/publications/index.html]
G[PDF<br/>vita/publications/resume-pubs.pdf]
H[Aggregated BibTeX<br/>vita/publications/resume-pubs.bib]
end
C --> CV
C --> PUBS
classDef toolkit fill:#22d3ee,color:#0f172a,stroke:#0891b2,stroke-width:2px;
classDef io fill:#f8fafc,color:#0f172a,stroke:#94a3b8;
classDef hidden fill:none,stroke:none;
classDef ioBoxes fill:#ffffde
class C toolkit;
class A,B,D,E,F,G,H io;
class L,R dot;
class CV,PUBS ioBoxes;
Table of Contents
The recommended interface is the wrapper script build-resume.sh, which runs everything inside a Docker image.
VITA_CONTAINER_ENGINE below)To install, download the build-resume.sh script and make it executable:
wget https://raw.githubusercontent.com/zzamboni/resume-toolkit/refs/heads/main/build-resume.sh
chmod a+rx build-resume.sh
The first time the script runs, it will download the Docker image automatically.
Build a Resume + publications:
build-resume.sh resume.json pubs-src/publications.bib
Build the bundled examples:
build-resume.sh samples/example-resume/example-resume.json --serve
or
build-resume.sh samples/john-doe-brilliantcv/john-doe-brilliantcv.json --serve
Then open http://localhost:8080 (the port may change if you run both at the same time, see the output for the correct URL).
Default output base directory:
build/<resume-stem>/Generated files:
build/<resume-stem>/vita/index.htmlbuild/<resume-stem>/vita/<resume-stem>.typbuild/<resume-stem>/vita/<resume-stem>.pdfbuild/<resume-stem>/vita/publications/index.htmlbuild/<resume-stem>/vita/publications/<resume-stem>-pubs.pdfbuild/<resume-stem>/vita/publications/<resume-stem>-pubs.bib$ build-resume.sh --help
Usage:
build-resume.sh [--pull] [build] <resume.json> [bibfiles...] [--out <dir>] [--pubs-url <url>] [--cv-url <url>] [--watch] [--serve] [--no-fetch-logos]
build-resume.sh [--pull] fetch-logos <resume.json> [--overwrite] [--dry-run] [--update-json] [--token LOGODEV_TOKEN]
build-resume.sh [--pull] update-logos <resume.json> [--overwrite] [--dry-run] [--token LOGODEV_TOKEN]
build-resume.sh [--pull] update-certs <username> <resume.json> [--include-expired] [--include-non-cert-badges] [--sort <date_desc|date_asc|name>]
build-resume.sh [--pull] update-pub-numbers <resume.json> [--html <path>]
build-resume.sh [--pull] version
build (default)build-resume.sh [--pull] [build] <resume.json> [bibfiles...] [--out <dir>] [--pubs-url <url>] [--cv-url <url>] [--watch] [--serve] [--no-fetch-logos]
These are equivalent:
build-resume.sh build resume.json pubs-src/publications.bib
build-resume.sh resume.json pubs-src/publications.bib
Options:
--out <dir>: output base directory (default build/<resume-stem>)--pubs-url <url>: online publications URL for standalone publications PDF footer (can be specified in the JSON file with meta.pdfthemeOptions.pubs_url)--cv-url <url>: online CV URL for main resume PDF footer (can be specified in the JSON file with meta.pdfthemeOptions.cv_url)--pull: pull the configured Docker image before running and use the updated image if one is available--watch: rebuild on input changes--serve: start HTTP server (implies --watch)--no-fetch-logos: disable automatic logo fetching when assets/logos/ is missingIf no BibTeX files are provided on the command line, the pipeline can read them from a special entry in the publications section of your JSON resume:
"publications": [
{
"authors": ["Example Person"],
"bibfiles": ["pubs.bib", "patents.bib"]
}
]
Only one publications[] entry may define bibfiles. If --bib arguments are provided, they take precedence. bibfiles entries are resolved relative to the JSON resume file location.
If no source assets/logos/ directory is found, the pipeline will automatically try to populate it by running the logo fetcher (see fetch-logos). If LOGODEV_TOKEN is not available, the build continues but emits a warning and skips automatic logo download. Use --no-fetch-logos to disable both the automatic fetch and the warning.
fetch-logos / update-logosDownload company/institution logos from the resume file into assets/logos/ in your working directory. Uses logo.dev to fetch logos. You need to create an API key and provide the publishable key in the LOGODEV_TOKEN environment variable, or using the --token flag.
If matching logo files are found under assets/logos/, the build step will include them automatically in the generated PDF. You can also provide/update the images by hand with the appropriate name (<company name>.png/jpg/jpeg/svg/webp/gif).
If called as update-logos or with the --update-json flag, it also updates the JSON resume file by writing the matching Logo.dev URLs into the image field of the corresponding work and education entries.
build-resume.sh fetch-logos resume.json
Options:
--overwrite: rewrite image files even if they already exist--dry-run: show what would be done--update-json: write image URLs back into the JSON file (in the image field of work/education entries)--token <token> (or set LOGODEV_TOKEN): publishable key from Logo.devupdate-certsSync certificates from Credly into your JSON resume. This replaces any entries in the certificates section of the JSONresume file that have a url field pointing to credly.com. Other entries are left untouched.
build-resume.sh update-certs <credly-username> resume.json
Options:
--include-expired--include-non-cert-badges--sort <date_desc|date_asc|name> (default date_desc)update-pub-numbersUpdate publication reference numbers in your JSON resume using the generated publications HTML anchors.
build-resume.sh update-pub-numbers resume.json
Options:
--html <path> (defaults to build/<resume-stem>/vita/publications/index.html)update-inline-pubsReplace inline publications[] entries in your JSON resume from the BibTeX selection defined by the generated-publications entry.
build-resume.sh update-inline-pubs resume.json
Optional BibTeX files can be passed explicitly to override the bibfiles configured in publications[]. The command keeps the single special publications[] entry with bibfiles and regenerates all other publications[] entries using the JSON Resume schema fields name, publisher, releaseDate, url, and summary.
build-resume.sh shell
Gives you an interactive shell inside the container.
The toolkit can read BibTeX sources from a special publications[] entry in your JSON Resume. This is the preferred way to define generated publications output. For example:
"publications": [
{
"authors": ["Example Person"],
"bibfiles": ["pubs.bib", "patents.bib"]
}
]
Rules for this entry:
publications[] entry may define bibfiles.bibfiles are resolved relative to the JSON resume file.name is omitted, it defaults to "Full list online".url is omitted, it defaults to "publications/".--bib arguments are provided on the command line, they take precedence over bibfiles from the JSON.That bibfiles entry is used to generate:
The regular JSON Resume publications[] entries are still rendered normally in the HTML CV. If you want those inline HTML publications to be generated from BibTeX, use update-inline-pubs.
The generated-publications entry may also define:
bibentries: explicit BibTeX entry keysbibkeywords: BibTeX keywords values to matchSelection is additive: an entry is included if it matches either bibentries or bibkeywords.
"publications": [
{
"authors": ["Example Person"],
"bibfiles": ["pubs.bib", "patents.bib"],
"bibentries": ["example2024paper"],
"bibkeywords": ["selected", "important"]
}
]
If meta.publicationsOptions.inline_in_pdf is enabled, the resume PDF embeds publications directly using Typst and pergamon. In this case any individually-specified entries in the JSON file are ignored.
inline_in_pdf is true, these defaults are used:
ref-style: "ieee"ref-full: trueref-sorting: "ydnt"inline_in_pdf is an object, you can override those values:
ref-styleref-fullref-sortingExample:
"meta": {
"publicationsOptions": {
"inline_in_pdf": {
"ref-style": "ieee",
"ref-full": false,
"ref-sorting": "ydnt"
}
}
}
The inline PDF bibliography always uses the filtered selection from bibentries / bibkeywords, when those are present.
meta.publicationsOptions.full_standalone_list controls whether the standalone publications outputs use the full list from bibfiles, or the same filtered subset used inline in the PDF CV.
true (default): standalone publications HTML/PDF/BibTeX use the full list, while the inline PDF bibliography can still be filteredfalse: standalone publications HTML/PDF/BibTeX use the same filtered subset as the inline PDF bibliographyYou can also set:
full_standalone_list_title: title for the standalone publications HTML/PDF pages
"Publications"You can configure publication sectioning for both the standalone publications page and the PDF bibliography outputs via meta.publicationsOptions:
pubSections: false or unset: no sectioning (single list)pubSections: true: use the default section order and titlespubSections: ["..."]: custom section order and selectionSection names are matched against BibTeX keywords. Optional title overrides go in:
pubSectionTitlesIf pubSections is true, these defaults are used:
DEFAULT_SECTION_ORDER = [
"book",
"editorial",
"thesis",
"refereed",
"techreport",
"presentations",
"invited",
"patent",
"other",
]
DEFAULT_SECTION_TITLES = {
"book": "Books",
"editorial": "Editorial Activities",
"thesis": "Theses",
"refereed": "Refereed Papers",
"techreport": "Technical Reports",
"presentations": "Presentations",
"invited": "Invited Talks and Articles",
"patent": "Patents",
"other": "Other Publications",
}
meta.publicationsOptions.links controls the floating links shown on the standalone publications HTML page.
If links is unset, these defaults are generated:
[
{
"name": "PDF",
"url": "<publications>.pdf",
"icon": "file-pdf"
},
{
"name": "BibTeX",
"url": "<publications>.bib",
"icon": "tex"
}
]
Notes:
<publications> is replaced with the generated publications file stem for the current resume<resume> is replaced with the main resume file stemlinks is present but empty ([]), no floating links are renderedfile-pdf, or class-style strings such as fa-regular fa-file-pdf or fa-brands fa-github"publications": [
{
"authors": ["Example Person"],
"bibfiles": ["pubs.bib", "patents.bib"],
"bibkeywords": ["selected", "important"],
"bibentries": ["example2024paper"]
}
],
"meta": {
"publicationsOptions": {
"inline_in_pdf": {
"ref-style": "ieee",
"ref-full": false,
"ref-sorting": "ydnt"
},
"full_standalone_list": true,
"full_standalone_list_title": "Research Output",
"links": [
{
"name": "PDF",
"url": "<publications>.pdf",
"icon": "file-pdf"
},
{
"name": "BibTeX",
"url": "<publications>.bib",
"icon": "tex"
}
],
"pubSections": ["refereed", "patent", "other"],
"pubSectionTitles": {
"refereed": "Journal Articles",
"patent": "Patents",
"other": "Other Publications"
}
}
}
The HTML theme used by this toolkit is jsonresume-theme-eventide, which is the source of truth for HTML theme configuration and behavior.
In resume-toolkit, all meta.themeOptions values are passed through to Eventide for HTML rendering. The toolkit also adds a few defaults before rendering:
meta.themeOptions.links is not set, default floating links are generated for the resume PDF and, when applicable, the standalone publications pagemeta.themeOptions.footer_right is not set, it defaults to Powered by [resume-toolkit](https://github.com/zzamboni/resume-toolkit)<resume> and <publications> placeholders in meta.themeOptions.links[*].url are expanded before renderingA small subset of meta.themeOptions also affects PDF rendering:
sections: controls section order and selection in both HTML and PDFsectionLabels: controls section labels in both HTML and PDFprojectsByType: controls project grouping in both HTML and PDFFor inline PDF publications, sectionLabels.publications is also used as the fallback publications section label unless overridden by meta.publicationsOptions.full_standalone_list_title.
PDF output is rendered with Typst using the brilliant-cv package. Toolkit-specific PDF options live under meta.pdfthemeOptions.
meta.pdfthemeOptions.layout is deep-merged into the default metadata.layout used for the generated Typst document.
Current defaults are:
DEFAULT_PDF_THEME_LAYOUT = {
"awesome_color": "skyblue",
"before_section_skip": "1pt",
"before_entry_skip": "1pt",
"before_entry_description_skip": "1pt",
"paper_size": "a4",
"fonts": {
"regular_fonts": ["Source Sans 3"],
"header_font": "Roboto",
},
"header": {
"header_align": "left",
"display_profile_photo": True,
"profile_photo_radius": "50%",
"info_font_size": "10pt",
},
"entry": {
"display_entry_society_first": True,
"display_logo": True,
},
"footer": {
"display_page_counter": False,
"display_footer": True,
},
}
Any fields you do not set keep these defaults.
Example:
{
"meta": {
"pdfthemeOptions": {
"layout": {
"awesome_color": "red",
"header": {
"header_align": "center",
"info_font_size": "9pt"
},
"footer": {
"display_page_counter": true
}
}
}
}
}
Three keys under meta.pdfthemeOptions.layout are handled specially by the toolkit rather than being passed directly into metadata.layout:
highlightedletterssummary_titlehighlighted and letters control how section titles are rendered in the generated Typst:
#cv-section(...)brilliant-cv uses its own defaultssummary_title controls whether a non-empty summary is preceded by a Summary heading in the PDF. It defaults to false.
Example:
{
"meta": {
"pdfthemeOptions": {
"layout": {
"highlighted": false,
"letters": 3,
"summary_title": true
}
}
}
}
At the meta.pdfthemeOptions level, the toolkit also supports:
visible_urlscv_urlpubs_urlvisible_urls controls where compact printable URLs are shown in the PDF output. It defaults to:
["notes"]
Supported values are:
notesprofilesprojectsallnonecv_url is shown in the footer of the main CV PDF.
pubs_url is shown in the footer of the standalone publications PDF.
Command-line --cv-url and --pubs-url values override these config entries.
Example:
{
"meta": {
"pdfthemeOptions": {
"visible_urls": ["notes", "profiles"],
"cv_url": "https://example.com/vita/",
"pubs_url": "https://example.com/vita/publications/"
}
}
}
If you set meta.site.url, relative links remain relative in HTML output but are resolved against that base URL in generated PDF output. This applies to:
url fieldssummary or highlightsThe standalone publications PDF uses the same meta.pdfthemeOptions.layout settings and section-title styling, but it also forces a few document-specific overrides:
meta.pdfthemeOptions.pubs_url is rendered in that footer when setSome behavior can be configured using environment variables. The only mandatory one (if you want to fetch logos) is LOGODEV_TOKEN.
LOGODEV_TOKEN: token used by fetch-logosVITA_PIPELINE_IMAGE: Docker image (default: ghcr.io/zzamboni/resume-toolkit:latest)VITA_CONTAINER_ENGINE: container engine to use (docker or podman). If unset, docker is used when available, otherwise podman.VITA_SERVE_PORT: serve port (default: 8080)VITA_PIPELINE_CACHE_DIR: host cache dir for container cachesMaintainer-oriented documentation now lives in DEVELOPMENT.md.
That guide covers:
mise tasksContent type
Image
Digest
sha256:7af308183…
Size
136.8 MB
Last updated
about 1 month ago
docker pull zzamboni/resume-toolkit