curriculr is an R package for producing data-driven curriculum vitae documents. You maintain your CV content in an Excel workbook. curriculr reads it, converts it into Typst layout blocks, and renders a polished PDF via Quarto’s Typst engine. No LaTeX. No vitae. No custom .cls files.
Installation
You can install curriculr from CRAN:
install.packages("curriculr")For the latest development features, install from GitHub:
# install.packages("pak")
pak::pak("erwinlares/curriculr")Getting started
Step 1 — scaffold your project
Call create_cv() with no arguments. This copies the template workbook and a placeholder profile image into your current working directory:
You will see:
v Created cv-data-template.xlsx
v Created placeholder.png
i Next steps:
1. Open cv-data-template.xlsx and fill in the profile sheet.
2. Replace placeholder.png with your own profile photo.
3. Call create_cv(data = 'cv-data-template.xlsx', photo = 'your-photo.png')
Step 2 — fill in the workbook
Open cv-data-template.xlsx. Start with the profile sheet:
| field | value |
|---|---|
| first_name | Your first name |
| last_name | Your last name |
| job_title | Your current title |
| address | Your mailing address |
| your@email.edu | |
| website | yourwebsite.com |
| github | your-github-username |
| in/your-linkedin | |
| profile_statement | One or two sentence professional summary |
| photo | Relative path to your profile image |
Then fill in the remaining sheets with your CV content. The readme sheet inside the workbook explains the column schema and date entry conventions in detail.
Step 3 — render
create_cv(
data = "cv-data-template.xlsx",
photo = "your-photo.png"
)This writes CV.qmd and CV.pdf next to your workbook. Open CV.pdf to review the output. To update your CV, edit the workbook and call create_cv() again with overwrite = TRUE.
To render without a profile photo, omit the photo argument. The header will use a single-column layout with your name, contact line, and profile statement centered on the page:
create_cv(data = "cv-data-template.xlsx")Rendering a resume
When you want a shorter, focused version of your CV, use variant = "resume". curriculr will include only the rows you have checked in the include_in_resume column of each section sheet:
create_cv(
data = "cv-data-template.xlsx",
photo = "your-photo.png",
variant = "resume",
output_file = "resume.pdf"
)Check and uncheck rows directly in the workbook. No R code changes are needed to switch between CV and resume variants.
Customizing the rendered PDF
Changing colors, fonts, and page layout
Open your workbook and edit the theme sheet. Each key maps to a visual setting:
| key | what it controls |
|---|---|
font_family |
Body font (e.g. Lato, Arial) |
font_size |
Base font size (e.g. 8.8pt) |
body_color |
Main text color (hex code) |
accent_color |
Section headings, dates, and rules (hex code) |
dark_color |
Entry titles and name in the header (hex code) |
papersize |
Page size (us-letter or a4) |
margin_x |
Left and right margins (e.g. 0.62in) |
margin_y |
Top and bottom margins (e.g. 0.58in) |
Re-render after editing the theme sheet with overwrite = TRUE to see the changes.
Changing section order or content
Edit the sections sheet in your workbook. Reorder rows to reorder sections. Delete a row to remove a section.
Adding a new section
Use add_section() to add a new sheet and register it in the sections control sheet in one step:
add_section(
"cv-data-template.xlsx",
section = "patents",
label = "Patents",
date_fun = "year_only"
)The new sheet is pre-populated with the standard column spine. Open the workbook, add your data, and re-render.
Functions
create_cv()
The main entry point. No arguments triggers scaffold mode. With data triggers render mode.
# Scaffold mode
create_cv()
# Render mode -- full CV with Font Awesome icons in the contact line
create_cv(
data = "cv-data.xlsx",
photo = "me.jpeg",
output_file = "erwin-lares-cv.pdf"
)
# Render mode -- resume variant, plain text contact line
create_cv(
data = "cv-data.xlsx",
photo = "me.jpeg",
variant = "resume",
use_icons = "none",
output_file = "erwin-lares-resume.pdf"
)Arguments:
-
data– path to the workbook.NULLtriggers scaffold mode. -
photo– path to the profile image.NULLrenders without a photo. -
output_file– PDF filename. Defaults to"CV.pdf". -
overwrite– whether to overwrite existing files. Defaults toFALSE. -
variant–"cv"(all rows) or"resume"(checked rows only). -
use_icons–"fontawesome"(default) or"none".
add_section()
Adds a new sheet to an existing workbook and registers it in the sections control sheet.
add_section(
"cv-data-template.xlsx",
section = "invited_talks",
label = "Invited Talks",
date_fun = "month_year",
where_col = "where"
)
read_cv_data()
Reads all sheets from the workbook into a named list. The profile and theme sheets become named character vectors; section sheets become data frames; the sections sheet is returned in row order.
cv <- read_cv_data("cv-data-template.xlsx")
cv <- read_cv_data("cv-data-template.xlsx", variant = "resume")
cv$experience # a data frame
cv$sections # the sections control sheet
cv$profile[["email"]] # a scalar string
cv$theme[["accent_color"]] # a scalar string
cv_contact_line()
Assembles the contact line from a profile vector. Useful when building custom Quarto templates.
cv_contact_line(cv$profile, use_icons = "fontawesome")
cv_contact_line(cv$profile, use_icons = "none")
cv_render_section()
Iterates over a CV data frame and writes each row as a formatted Typst entry. Called inside CV.qmd – you will not normally call this directly.
typst_escape()
Escapes Typst-sensitive characters in a string. Useful when building custom Quarto templates.
Workbook schema
Every section sheet shares a common column spine:
title | unit | startMonth | startYear | endMonth | endYear | where | detail | include_in_resume
title is always the primary entry label. unit is the secondary line. include_in_resume is a boolean checkbox column – check a row to include it when rendering with variant = "resume". Leave cells blank rather than typing NA.
Migration notes
Detailed notes on upgrading from previous versions are available in the changelog. The key changes by version:
v0.2.0 to v0.3.0 – photo = NULL now produces a no-photo layout instead of falling back to a placeholder. Workbooks need an include_in_resume column on every section sheet. An optional theme sheet controls fonts, colors, and page layout. openxlsx2 replaces readxl.
v0.1.0 to v0.2.0 – create_cv() gained scaffold mode (no arguments) and render mode (with arguments). Workbooks need a sections sheet to control which sections appear and in what order.
Related packages
curriculr shares an author and design philosophy with three other R packages focused on reproducible research workflows:
- toolero – research project scaffolding and data wrangling utilities
- containr – containerization of R projects via Dockerfile generation
- submitr – job submission to UW-Madison’s CHTC from inside R
Together, toolero, containr, and submitr form the From the Notebook to the Cluster pipeline. curriculr is independent but follows the same conventions: small focused functions, data-driven workflows, and Quarto as the publishing layer.
Acknowledgements
curriculr was inspired by two prior projects:
- vitae by Mitchell O’Hara-Wild, Rob Hyndman, and contributors
- Awesome CV by Byungjin Park (posquit0)
