Convert Your Markdown Resume to ATS-Friendly PDF and DOCX
Introduction
As a developer, I spend most of my time writing in Markdown. It is simple, portable, and version-controllable. So when it came time to update my resume, I asked myself: why not write it in Markdown too?
The problem is that recruiters and Applicant Tracking Systems (ATS) do not accept Markdown files. They need PDF or DOCX formats with clean, parseable layouts. After searching for existing solutions and finding them either too complex or lacking customization options, I decided to build my own tool.
The result is MD2CV – an open-source Markdown to resume converter that generates ATS-friendly PDF and DOCX files with customizable templates.
In this post, I will walk you through the features, installation process, and practical usage of MD2CV.
What is MD2CV?
MD2CV is a command-line tool that converts Markdown files into professional resume documents. It is designed with the following goals in mind:
- Simplicity: Write your resume in plain Markdown with YAML frontmatter for metadata
- ATS Compatibility: Generated documents use standard fonts and clean layouts that ATS systems can parse
- Multiple Formats: Export to both PDF and DOCX from a single source file
- Template System: Choose from built-in templates or create your own
- Docker Support: No dependency headaches – just run with Docker
The project is open-source and available on GitHub: github.com/cagatayuresin/md2cv
Why Markdown for Resumes?
Before diving into the technical details, let me explain why Markdown is an excellent choice for writing resumes:
Version Control
Your resume is a living document that evolves throughout your career. With Markdown, you can track every change using Git. Want to see what your resume looked like two years ago? Just check out an older commit.
Single Source of Truth
Instead of maintaining separate files for different formats, you maintain one Markdown file. Need a PDF? Generate it. Need a DOCX for that recruiter who specifically asked for Word format? Generate that too. Both come from the same source.
Focus on Content
Markdown forces you to focus on what matters: the content. No fiddling with margins, font sizes, or spacing while writing. Those decisions are handled by templates.
Portability
A Markdown file is just plain text. It opens anywhere, on any device, with any editor. Twenty years from now, you will still be able to read it.
Key Features
YAML Frontmatter for Metadata
MD2CV uses YAML frontmatter to store your contact information and metadata separately from the content:
---
name: "John Doe"
title: "Senior Software Engineer"
email: "john.doe@example.com"
phone: "+1 555 123 4567"
location: "San Francisco, CA"
linkedin: "linkedin.com/in/johndoe"
github: "github.com/johndoe"
website: "johndoe.dev"
---
# Professional Summary
Your content starts here...
Code language: YAML (yaml)
This separation allows templates to render contact information consistently while you focus on writing the main content.
Multiple Template Options
MD2CV includes three built-in templates:
| Template | Description | Best For |
|---|---|---|
| ats_classic | Traditional design with serif fonts | Conservative industries, large corporations |
| modern | Contemporary look with blue accents | Tech companies, startups |
| minimal | Clean, simple layout | Design-focused roles, creative industries |
Each template is fully customizable. You can modify the existing ones or create entirely new templates.
Dual Format Export
Generate both PDF and DOCX from a single command. The PDF is rendered using WeasyPrint for high-quality output with full CSS support. The DOCX is generated using python-docx with proper styling for Microsoft Word compatibility.
Docker-First Approach
The tool is designed to run in Docker, eliminating the need to install system dependencies like Pango or Cairo on your local machine. This ensures consistent output across different operating systems.
Installation
Prerequisites
You need Docker installed on your system. If you do not have Docker yet:
- macOS: Download from docker.com or install via Homebrew with
brew install --cask docker - Windows: Download Docker Desktop from the official website
- Linux: Follow the installation instructions for your distribution
Getting MD2CV
Clone the repository:
git clone https://github.com/cagatayuresin/md2cv.gitcd md2cvCode language: Bash (bash)
Build the Docker image:
docker build -t md2cv .Code language: Bash (bash)
That is it. You are ready to convert resumes.
Usage Guide
Basic Conversion
To convert a Markdown resume to both PDF and DOCX:
docker run --rm \
-v "$(pwd)/input:/app/input:ro" \
-v "$(pwd)/templates:/app/templates:ro" \
-v "$(pwd)/output:/app/output" \
md2cv /app/input/my_resume.md --format allCode language: Bash (bash)
Let me break down this command:
docker run --rm: Run a container and remove it when done-v "$(pwd)/input:/app/input:ro": Mount your input directory as read-only-v "$(pwd)/templates:/app/templates:ro": Mount templates as read-only-v "$(pwd)/output:/app/output": Mount output directory for generated filesmd2cv: The image name/app/input/my_resume.md: Path to your Markdown file inside the container--format all: Generate both PDF and DOCX
Choosing a Template
Use the --template flag to select a specific template:
docker run --rm \
-v "$(pwd)/input:/app/input:ro" \
-v "$(pwd)/templates:/app/templates:ro" \
-v "$(pwd)/output:/app/output" \
md2cv /app/input/my_resume.md --template modern --format pdfCode language: Bash (bash)
Listing Available Templates
To see all available templates:
docker run --rm \
-v "$(pwd)/templates:/app/templates:ro" \
md2cv --list-templatesCode language: Bash (bash)
Output:
Available templates:
----------------------------------------
✓ ats_classic
✓ modern
✓ minimal
Format Options
| Flag | Result |
|---|---|
--format pdf | Generate PDF only |
--format docx | Generate DOCX only |
--format all | Generate both formats |
Writing Your Resume
Starting from the Template
The repository includes a sample template at examples/template_cv.md. Copy it to create your own:
cp examples/template_cv.md input/my_resume.mdCode language: Bash (bash)
Resume Structure
Here is the recommended structure:
---
name: "Your Name"
title: "Your Title"
email: "your.email@example.com"
phone: "+1 555 123 4567"
location: "City, Country"
linkedin: "linkedin.com/in/yourprofile"
github: "github.com/yourusername"
website: "yourwebsite.com"
---
# Professional Summary
A brief 2-3 sentence overview of your experience and expertise.
---
# Work Experience
## Job Title
**Company Name** | Location | Start Date - End Date
- Achievement using action verbs and metrics
- Another accomplishment with quantifiable results
- Third bullet point demonstrating impact
## Previous Job Title
**Previous Company** | Location | Dates
- Relevant achievements
- More accomplishments
---
# Education
## Degree Name
**University Name** | Graduation Year
- GPA: X.XX/4.00 (if notable)
- Relevant coursework or honors
---
# Skills
## Programming Languages
Python, JavaScript, Go, SQL
## Technologies
Docker, Kubernetes, PostgreSQL, Redis
## Languages
- English: Native
- Spanish: Intermediate
---
# Certifications
- **Certification Name** - Issuing Organization, Year
---
# Projects
## Project Name
Brief description of what you built and the technologies used.Code language: Markdown (markdown)
Formatting Tips
Use standard Markdown formatting:
#for main sections (Professional Summary, Work Experience, etc.)##for subsections (job titles, degrees)**bold**for company names-for bullet points---for horizontal rules between sections
The converter handles the translation to appropriate formatting in both PDF and DOCX output.
Creating Custom Templates
MD2CV uses Jinja2 for templating and CSS for styling. To create a custom template:
Step 1: Create a Template Directory
mkdir templates/my_custom_template
Step 2: Create template.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ meta.name }} - Resume</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<header>
<h1>{{ meta.name }}</h1>
<p class="title">{{ meta.title }}</p>
<div class="contact">
<span>{{ meta.email }}</span>
<span>{{ meta.phone }}</span>
<span>{{ meta.location }}</span>
</div>
</header>
<main>
{{ content | safe }}
</main>
</div>
</body>
</html>Code language: HTML, XML (xml)
Available template variables:
{{ meta.name }}– Full name{{ meta.title }}– Job title{{ meta.email }}– Email address{{ meta.phone }}– Phone number{{ meta.location }}– Location{{ meta.linkedin }}– LinkedIn URL{{ meta.github }}– GitHub URL{{ meta.website }}– Personal website{{ content | safe }}– Rendered Markdown content
Step 3: Create style.css
body {
font-family: 'Helvetica', Arial, sans-serif;
font-size: 11pt;
line-height: 1.5;
color: #333;
max-width: 210mm;
margin: 0 auto;
padding: 20mm;
}
header {
text-align: center;
margin-bottom: 20px;
border-bottom: 2px solid #333;
padding-bottom: 15px;
}
h1 {
font-size: 24pt;
margin-bottom: 5px;
}
.title {
font-size: 12pt;
color: #666;
}
.contact span {
margin: 0 10px;
}
main h1 {
font-size: 14pt;
text-transform: uppercase;
border-bottom: 1px solid #ccc;
margin-top: 20px;
}
main h2 {
font-size: 12pt;
margin-top: 15px;
}
ul {
margin-left: 20px;
}
@media print {
body {
padding: 15mm;
}
}Code language: CSS (css)
Step 4: Use Your Template
docker run --rm \
-v "$(pwd)/input:/app/input:ro" \
-v "$(pwd)/templates:/app/templates:ro" \
-v "$(pwd)/output:/app/output" \
md2cv /app/input/my_resume.md --template my_custom_templateCode language: Bash (bash)
Technical Implementation
For those interested in the technical details, here is how MD2CV works under the hood:
Architecture
The converter follows a straightforward pipeline:
- Parse: Read the Markdown file and extract YAML frontmatter
- Convert: Transform Markdown to HTML using the Python markdown library
- Render: Apply the selected Jinja2 template with metadata and content
- Export PDF: Use WeasyPrint to convert HTML/CSS to PDF
- Export DOCX: Parse Markdown directly and build a Word document using python-docx
Key Dependencies
| Library | Purpose |
|---|---|
| markdown | Parse Markdown to HTML |
| Jinja2 | Template rendering |
| WeasyPrint | HTML/CSS to PDF conversion |
| python-docx | DOCX generation |
| PyYAML | YAML frontmatter parsing |
Why WeasyPrint?
WeasyPrint was chosen for PDF generation because it provides excellent CSS support, including:
- Flexbox layouts
- Web fonts
- Print-specific media queries
- Page break control
This allows templates to use modern CSS while producing high-quality PDF output.
Why Docker?
WeasyPrint requires system libraries (Pango, Cairo) that can be difficult to install on some systems. Docker encapsulates these dependencies, ensuring the tool works identically regardless of the host operating system.
ATS Compatibility Tips
When writing your resume, keep these tips in mind for maximum ATS compatibility:
Do
- Use standard section headings (Work Experience, Education, Skills)
- Stick to common fonts (Arial, Georgia, Times New Roman)
- Use bullet points for achievements
- Include keywords from job descriptions
- Keep formatting simple and consistent
Avoid
- Tables for layout (ATS systems struggle to parse them)
- Headers and footers with important information
- Graphics or images
- Unusual fonts or icons
- Multiple columns
The built-in templates are designed with these guidelines in mind, especially ats_classic which prioritizes parseability over visual flourish.
Comparison with Other Tools
| Feature | MD2CV | LaTeX Resume | Online Builders |
|---|---|---|---|
| Plain text source | Yes | Yes | No |
| Version control friendly | Yes | Yes | No |
| No account required | Yes | Yes | No |
| DOCX export | Yes | Limited | Varies |
| Custom templates | Yes | Yes | Limited |
| Learning curve | Low | High | Low |
| Runs offline | Yes | Yes | No |
Roadmap
Planned features for future releases:
- Additional built-in templates
- Cover letter support
- Multiple language support in templates
- Web interface for non-technical users
- Template marketplace
Conclusion
MD2CV bridges the gap between the developer-friendly Markdown format and the recruiter-expected PDF and DOCX formats. It maintains the benefits of plain text source files while producing professional, ATS-compatible output.
If you are a developer who prefers writing in Markdown and wants full control over your resume format, give MD2CV a try. The project is open-source and contributions are welcome.
Repository: github.com/cagatayuresin/md2cv
License: MIT