How to maintain a master resume for several roles and formats

A practical guide to maintaining a single, structured resume that can be automatically tailored to different roles and converted to any format.
job market
Author

Eivind Otto Hjelle

Published

May 14, 2025

When applying for jobs, it is important to ensure that your resume is well-structured and relevant to the positions you are applying for. But exactly what counts as “relevant” depends on the position, and without a good system you will find yourself editing several versions of your resume over and over again. This post arose out of my own desire to streamline this entire process, from adding new experiences to my resume to tailoring it to specific roles.

Naturally, a lot of people have already thought about this problem. There are many tools and services that are made for writing resumes, some of which require hefty usage fees. In this post, I suggest a solution that is so simple and obvious in hindsight that no one else has bothered to write about it.

The idea is to use a simple structured format, YAML, as the ground truth, and templates to turn the YAML resume into other formats like LaTeX, HTML, or whatever else you prefer. In more details, the benefits of this approach is that it allows you to:

Let’s explore why this approach works better than traditional methods.

Generate different versions of your resume from one source of truth.

Why YAML?

Three common approaches and why I moved away from them:

The Word Document Approach

An approach I’ve been using over the last year is to maintain a single resume in Word document, as this is recommended by many sources.1 However, this has some drawbacks. Since docx is a binary format, it is not friendly to version control, making it more cumbersome to maintain multiple versions for different roles. It also requires special software to view or edit, which makes it difficult to work with using programming tools.

1 A big part of why Word documents are recommended is that they tend to be friendly to Applicant Tracking Systems (ATS). But PDF generated with LaTeX can also be compatible with ATS, if careful attention is paid to the layout.

The Markdown / Asciidoc Approach

One idea I had was to maintain a single “master resume” in Markdown format, which is a text-based format that is easy to maintain and edit, and set up workflows for converting it to different formats. It’s easy to find several examples of this online, such as here and here.

The main disadvantage is losing control over formatting, often resulting in unattractive documents. While there are tools to help, they all follow the same basic strategy:

  1. Convert the Markdown document to a more structured format like JSON.
  2. Convert the structured format to the desired format.

More concretely, there are two main approaches. The first is to generate an HTML file from Markdown, controlling styling with a custom CSS file, and then convert the HTML file to the desired format, for example by printing it to a PDF. The HTML will look nice, but the PDF may not. The second approach is to rely on a powerful tool like pandoc, which can convert between different formats. Again, the final document may not look the way you want it to. This is not an insurmountable problem, but from what I can tell, it can be challenging to get the styling just right.

A similar approach to the Markdown approach is to use a richer text-based format like Asciidoc. Using Asciidoc has the advantage over Markdown that it may be somewhat easier to wrestle with the formatting. But just like with Markdown, it ultimately feels like trying to make a silk purse out of a sow’s ear.

The YAML Solution

It is easy to convert from a highly structured format to a less structured format, but not the other way around. This realization led me to structured file formats like JSON and YAML.

I’m not the first person to have this idea. In fact, there is a whole community of people advocating for a JSON-based standard for resumes, and various different tools for converting resumes from structured formats like YAML to other formats.

However, I’m advocating for a slightly different approach. Instead of providing a comprehensive package, my suggestion is to use a few lines of code to convert a YAML file into other formats using jinja2 templates. This doesn’t adhere to any strict standards, but it’s simple and flexible, and can be adapted to many different use cases.

I chose to use YAML over JSON because it’s more human-readable and doesn’t require quotes around strings or commas between items.

The YAML resume: A simple example

Here is an example of a YAML resume (click to expand):

Geppetto’s YAML resume
name: Geppetto
contact:
  location: Villaggio Incantato, Italy
  date_of_birth: March 12, 1820
  citizenship: Italy
  email: geppetto@woodmail.it
  phone: +39 123 456 7890
  github: https://github.com/geppetto-works

summary:
  - text: |
      Master woodcarver with a lifelong dedication to handcraft, toy design, and mechanical storytelling.
      Combines traditional techniques with creative engineering to build expressive and enduring works.
      Looking to contribute craftsmanship and care to meaningful creative projects.

education:
  - institution: Guild of Master Carvers
    degree: Journeyman Woodworker Certification
    date: 1842
    location: Florence, Italy

  - institution: Independent Study
    degree: Apprenticeship in Automata Construction and Puppet Mechanics
    date: 1845
    location: Venice, Italy

experience:
  - organization: Geppetto's Workshop
    location: Villaggio Incantato, Italy
    role: Master Woodcarver and Toymaker
    start: January 1850
    end: Present
    bullets:
      - Designed and handcrafted over 300 wooden toys including animals, puppets, and musical automata.
      - Created Pinocchio, an autonomous puppet capable of emotional response and ethical reasoning.
      - Offered sliding-scale toy repairs and creations for families in the village.
      - Built puppet theaters with hand-cranked scenery for school performances.
      - Developed innovative joint mechanisms for enhanced puppet mobility and expression.
      - Mentored 15 apprentices in traditional woodcarving techniques and mechanical design.
      - Invented a self-playing musical box system using wooden gears and wind-up mechanisms.
      - Established a community workshop program teaching basic woodworking to village children.
      - Created custom mechanical toys for special needs children to aid in motor skill development.

  - organization: Puppet Theater of Tuscany
    location: Tuscany, Italy
    role: Set Designer and Puppet Articulator
    start: June 1848
    end: December 1849
    bullets:
      - Designed stage mechanisms and built expressive puppets for traveling shows.
      - Worked with performers to enhance articulation through mechanical design.

projects:
  - title: Pinocchio
    date: Ongoing
    description: >
      A fully articulated wooden puppet designed for emotional expressiveness and narrative-constrained learning.
      Combines handcrafted form with emergent behavioral systems and ethical instruction frameworks.
    url: https://en.wikipedia.org/wiki/Pinocchio

  - title: Whistle-toy Orchestra
    date: March 1885
    description: >
      A set of carved whistle-operated instruments that harmonize through tuned airflow and puppet-assisted actuation.
      Created to teach children musical structure through playful experimentation.

honors:
  - title: Best Toymaker in Tuscany
    description: Awarded by the Tuscany Chamber of Artisans for craftsmanship, community impact, and imaginative design.
    date: December 1883

  - title: Patron of the Children's Guild
    description: Recognized for mentorship and generosity supporting village youth creative expression.
    date: June 1886

publications:
  - title: "The Heart Inside the Wood: Designing for Growth"
    type: Preprint (submitted)
    date: 1881

  - title: "Whimsy and Will: Puppetry as a Medium for Ethical Development"
    type: Symposium Proceedings
    date: 1880

  - title: "Toymaking for the Soul: A Handbook for Village Craft Educators"
    type: Community Education Manual
    date: 1876
    coauthors:
      - Silvino Boccadutti

  - title: On the Practical Construction of Puppet Joints
    type: Instructional Manual
    date: 1874

This YAML resume can be converted to other formats using jinja2 templates and a few lines of code. I’ll get back to the templates later, but first, let’s look at the code for rendering the resume to a different format, for example tex:

import yaml
from pathlib import Path
from jinja2 import Template

FORMAT = "tex" # Change this to a different format if you want

# Load resume data
resume_data = yaml.safe_load(Path(f"resume.yaml").read_text())

# Load and render template
with open(f"resume.{FORMAT}.j2") as f:
    template = Template(f.read())
    output = template.render(**resume_data)

# Write output
Path(f"resume.{FORMAT}").write_text(output)
print(f"Resume rendered to resume.{FORMAT}")

Here is a simple example of a tex template:

Jinja2 template for tex
\documentclass[10pt]{article}
\usepackage[margin=0.75in]{geometry}
\usepackage{enumitem}
\usepackage{titlesec}
\usepackage{hyperref}
\usepackage{xcolor}

% Customize hyperlink appearance
\definecolor{darkblue}{RGB}{0,0,120}
\hypersetup{
    colorlinks=true,
    linkcolor=darkblue,
    filecolor=darkblue,
    urlcolor=darkblue,
}

% No paragraph indentation
\setlength{\parindent}{0pt}
% \setlength{\parskip}{0.5em} % Optional: adds space between paragraphs

% Section formatting
\titleformat{\section}
    {\normalsize\bfseries\uppercase}
    {}{0em}{}[\titlerule]
\titlespacing*{\section}
    {0pt}{1.5ex plus 1ex minus .2ex}{1ex plus .2ex}

% Custom commands for better spacing
\newcommand{\spaced}[1]{\vspace{0.3em}#1\vspace{0.3em}}

\begin{document}

% Header
\begin{center}
    {\Large\bfseries{ {{- name -}} }}\\[0.2em]
    {\normalsize
        \href{mailto:{{ contact.email }}}{ {{- contact.email -}} } ~|~
        \href{tel:{{ contact.phone }}}{ {{- contact.phone -}} } ~|~
        \href{ {{- contact.github -}} }{GitHub}
    }
\end{center}

\vspace{0.5em}

% Summary
{% if summary %}
\section*{Summary}
{% for s in summary %}
{{ s.text }}
{% endfor %}
{% endif %}

% Experience
\section*{Experience}
{% for job in experience %}
\textbf{ {{- job.organization -}} }, \hfill {{ job.location }} \\
\textit{ {{- job.role -}} }, \hfill {{ job.start }} -- {{ job.end }}
\begin{itemize}[leftmargin=*, noitemsep, topsep=0.1em]
{% for b in job.bullets %}
    \item {{ b }}
{% endfor %}
\end{itemize}
\vspace{0.3em}
{% endfor %}

% Projects
\section*{Projects}
{% for p in projects %}
\textbf{\href{ {{- p.url -}} }{ {{- p.title -}} }}, \hfill {{ p.date }} \\
{{ p.description }} \\
\vspace{0.3em}
{% endfor %}

% Education
\section*{Education}
{% for ed in education %}
\textbf{ {{- ed.institution -}}, } \hfill {{ ed.location }} \\
{{ ed.degree }}, \hfill {{ ed.date }}
\vspace{0.3em}
{% endfor %}

% Honors and Awards
\section*{Honors and Awards}
{% for award in honors %}
\textbf{ {{- award.title -}},} \hfill {{ award.date }} \\
{{ award.description }}
\vspace{0.3em}
{% endfor %}

% Publications
\section*{Publications}
\begin{itemize}[leftmargin=*, noitemsep, topsep=0.1em]
{% for pub in publications %}
    \item \textit{\href{ {{- pub.url -}} }{ {{- pub.title -}} }}{% if pub.coauthors %}, with {{ pub.coauthors | join(", ") }}{% endif %}. {{ pub.type }}.{% if pub.journal %} {{ pub.journal }} ({{ pub.date }}).{% endif %}
{% endfor %}
\end{itemize}

\end{document}

Running the code produces a tex file like this:

Geppetto’s tex resume
\documentclass[10pt]{article}
\usepackage[margin=0.75in]{geometry}
\usepackage{enumitem}
\usepackage{titlesec}
\usepackage{hyperref}
\usepackage{xcolor}

% Customize hyperlink appearance
\definecolor{darkblue}{RGB}{0,0,120}
\hypersetup{
    colorlinks=true,
    linkcolor=darkblue,
    filecolor=darkblue,
    urlcolor=darkblue,
}

% No paragraph indentation
\setlength{\parindent}{0pt}
% \setlength{\parskip}{0.5em} % Optional: adds space between paragraphs

% Section formatting
\titleformat{\section}
    {\normalsize\bfseries\uppercase}
    {}{0em}{}[\titlerule]
\titlespacing*{\section}
    {0pt}{1.5ex plus 1ex minus .2ex}{1ex plus .2ex}

% Custom commands for better spacing
\newcommand{\spaced}[1]{\vspace{0.3em}#1\vspace{0.3em}}

\begin{document}

% Header
\begin{center}
    {\Large\bfseries{Geppetto}}\\[0.2em]
    {\normalsize
        \href{mailto:geppetto@woodmail.it}{geppetto@woodmail.it} ~|~
        \href{tel:+39 123 456 7890}{+39 123 456 7890} ~|~
        \href{https://github.com/geppetto-works}{GitHub}
    }
\end{center}

\vspace{0.5em}

% Summary

\section*{Summary}

Master woodcarver with a lifelong dedication to handcraft, toy design, and mechanical storytelling.
Combines traditional techniques with creative engineering to build expressive and enduring works.
Looking to contribute craftsmanship and care to meaningful creative projects.




% Experience
\section*{Experience}

\textbf{Geppetto's Workshop}, \hfill Villaggio Incantato, Italy \\
\textit{Master Woodcarver and Toymaker}, \hfill January 1850 -- Present
\begin{itemize}[leftmargin=*, noitemsep, topsep=0.1em]

    \item Designed and handcrafted over 300 wooden toys including animals, puppets, and musical automata.

    \item Created Pinocchio, an autonomous puppet capable of emotional response and ethical reasoning.

    \item Offered sliding-scale toy repairs and creations for families in the village.

    \item Built puppet theaters with hand-cranked scenery for school performances.

    \item Developed innovative joint mechanisms for enhanced puppet mobility and expression.

    \item Mentored 15 apprentices in traditional woodcarving techniques and mechanical design.

    \item Invented a self-playing musical box system using wooden gears and wind-up mechanisms.

    \item Established a community workshop program teaching basic woodworking to village children.

    \item Created custom mechanical toys for special needs children to aid in motor skill development.

\end{itemize}
\vspace{0.3em}

\textbf{Puppet Theater of Tuscany}, \hfill Tuscany, Italy \\
\textit{Set Designer and Puppet Articulator}, \hfill June 1848 -- December 1849
\begin{itemize}[leftmargin=*, noitemsep, topsep=0.1em]

    \item Designed stage mechanisms and built expressive puppets for traveling shows.

    \item Worked with performers to enhance articulation through mechanical design.

\end{itemize}
\vspace{0.3em}


% Projects
\section*{Projects}

\textbf{\href{https://en.wikipedia.org/wiki/Pinocchio}{Pinocchio}}, \hfill Ongoing \\
A fully articulated wooden puppet designed for emotional expressiveness and narrative-constrained learning. Combines handcrafted form with emergent behavioral systems and ethical instruction frameworks.
 \\
\vspace{0.3em}

\textbf{\href{}{Whistle-toy Orchestra}}, \hfill March 1885 \\
A set of carved whistle-operated instruments that harmonize through tuned airflow and puppet-assisted actuation. Created to teach children musical structure through playful experimentation.
 \\
\vspace{0.3em}


% Education
\section*{Education}

\textbf{Guild of Master Carvers, } \hfill Florence, Italy \\
Journeyman Woodworker Certification, \hfill 1842
\vspace{0.3em}

\textbf{Independent Study, } \hfill Venice, Italy \\
Apprenticeship in Automata Construction and Puppet Mechanics, \hfill 1845
\vspace{0.3em}


% Honors and Awards
\section*{Honors and Awards}

\textbf{Best Toymaker in Tuscany,} \hfill December 1883 \\
Awarded by the Tuscany Chamber of Artisans for craftsmanship, community impact, and imaginative design.
\vspace{0.3em}

\textbf{Patron of the Children's Guild,} \hfill June 1886 \\
Recognized for mentorship and generosity supporting village youth creative expression.
\vspace{0.3em}


% Publications
\section*{Publications}
\begin{itemize}[leftmargin=*, noitemsep, topsep=0.1em]

    \item \textit{\href{}{The Heart Inside the Wood: Designing for Growth}}. Preprint (submitted).

    \item \textit{\href{}{Whimsy and Will: Puppetry as a Medium for Ethical Development}}. Symposium Proceedings.

    \item \textit{\href{}{Toymaking for the Soul: A Handbook for Village Craft Educators}}, with Silvino Boccadutti. Community Education Manual.

    \item \textit{\href{}{On the Practical Construction of Puppet Joints}}. Instructional Manual.

\end{itemize}

\end{document}

Finally, compile the tex to a pdf:

The upshot is that it’s easy to maintain and edit the resume in YAML format, and to control the style of the final document with a jinja2 template. Of course, it’s also possible to make jinja2 templates for HTML, Markdown, or other formats.

One resume to rule them all

The above works for one resume in multiple formats. To target different roles, tag items in the YAML (e.g., all, woodworking, robotics) and generate role‑specific resumes by filtering on tags. Optionally, use an LLM or other tools for light phrasing tweaks2.

2 In the end, I haven’t found the LLM suggestions to be helpful, but the feature is still in the accompanying repository. It can probably be improved by better prompting and fine-tuning.

This lets you keep one master resume while producing focused versions per role with minimal effort.

A practical implementation

The accompanying GitHub repository provides a simple CLI tool that enables the following workflow:

  1. Filtering: resume generate --role <role> to create a role‑specific YAML file from the master file.
  2. Review: Optionally pass --job <desc.txt> to lightly refine phrasing with an LLM, or edit manually.
  3. Rendering: resume render --role <role-template> to produce documents via your jinja2 templates.

If you go to the repository, you can also see an example of Geppetto’s resume with tags, and the resulting resume files for different roles.