# markdown-resume and the local-first resume editor built for ATS parsers

> Markdown Resume is a browser-based editor where your resume is a Markdown file, the preview is paginated like paper, and export produces PDF, Markdown, self-contained HTML or DOCX. Nothing leaves your machine because the storage is IndexedDB, which is the right call for a document that describes your life, and also means your resumes are not synced between machines.

**junian/markdown-resume** — Write Resume with Markdown in ATS and Human-friendly format. Free and Open Source, Privacy-friendly, Local-first resume builder. Simple, private, local.

- Repository: https://github.com/junian/markdown-resume
- Website: https://www.junian.dev/markdown-resume/
- Stars: 706 · Forks: 152
- Language: Vue
- License: AGPL-3.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/junian-markdown-resume

## A resume that is a text file first

Markdown Resume is described as a local-first editor for creating clean, ATS-friendly resumes with Markdown, combining a code editor with a paginated live preview, practical formatting controls and self-contained export options.

The pitch to developers is that you write a Markdown file, and everything else is derived from it. The editor is a code editor with a live preview, so the source of truth is text you could commit to a private repository and diff like any other document.

The second thing the project does is address ATS parsing directly. The default template is based on CareerCup's resume template, using a restrained layout, web-safe fonts and a readable content structure so a resume works well both for applicant tracking systems and for people. Web-safe fonts and a single column are not a stylistic accident here, they are the point, since an ATS reads a document structure rather than a visual design and a two-column layout is a common way to scramble one.

The author is careful about claims, saying he cannot guarantee that using this will improve your job search success rate, and that he hopes it helps. That restraint is worth noting in a project whose entire value proposition is about getting past a machine.

The language of the interface is English and Indonesian, and the licence is AGPL-3.0 rather than anything permissive, which matters for a self-hostable web app and is covered below.

## Storage in IndexedDB means no account and no sync

The privacy story is architectural rather than a promise. Your resumes, images and settings stay in your browser, no account is required, and your resume content is not uploaded to an application server.

The storage mechanism is named in the feature list: data is saved locally in your browser using IndexedDB, with the localForage repository linked for details. That is the same layer the images use, so a resume and its embedded pictures live in one place.

The project also gives you control over that storage rather than hiding it. There are local storage usage estimates, refresh controls and a protected factory-reset action, so you can see what you are using and clear it deliberately.

The trade is the one a local-first design always makes. Without an account there is no sync, no backup across devices, and no collaboration. The feature list has multiple resume management, with the ability to manage, rename, duplicate, import, back up and delete, which is a good sign for someone working on several versions, but the import and backup are manual operations.

The README also carries a notice recommending a Chromium-based browser such as Chrome or Microsoft Edge. The project works offline as a PWA, so once loaded it does not need a network, but the initial experience and the print and export paths are evidently best supported in that browser family.

## Export targets and why self-contained matters

The export list is the practical half of the feature set: PDF, Markdown, self-contained HTML, and DOCX, with A4 and US Letter paper sizes.

Markdown export is the round trip, the file you already have. DOCX is what an application form usually wants. PDF is what you print and what most people actually send. And self-contained HTML is the one that solves a problem you might not have thought about, since a single HTML file with everything inlined can be emailed, archived, or opened without a server.

The word self-contained is doing specific work in the image story. When exporting to HTML or DOCX, image references are automatically replaced with inline base64 data URLs, so the exported file carries its own pictures rather than pointing at a path that will not resolve on someone else's machine. That is exactly the kind of failure that makes a resume silently lose a photo when it is converted by a third party.

Alongside export there is a set of formatting controls that map to the way people actually write resumes. Page margins, theme colors, line heights and fonts are all adjustable, custom CSS is supported, and there is light document previews in every color theme. Automatic page breaking handles the pagination, and you can add line breaks with a LaTeX-style escape or start a new page.

TeX support through KaTeX is there, along with cross-referencing for academic CVs, and a case correction feature that turns Github into GitHub.

## The image gallery and the service worker URL scheme

The Image Gallery is the feature that goes furthest beyond a text editor, and it has a specific mechanism worth understanding.

You upload an image in the gallery, and each image then gets a stable URL in the format ./images/<id>, served by a Service Worker. The point of that scheme is that no external hosting is needed, since the file never leaves the browser, and the URL is stable enough to paste into your Markdown and have it keep working.

The Markdown form is:

```markdown
![My photo](./images/1234567890_abc123)
```

Or, if you prefer the HTML form:

```html
<img src="./images/1234567890_abc123" alt="My photo" />
```

And the privacy statement is unambiguous: images are stored entirely inside your browser's IndexedDB, the same storage used for your resumes, and they are never uploaded to any server and never leave your computer.

There is one more detail that is easy to miss. The feature list mentions fixing legacy Iconify markup from older resumes and saving the migrated content, which tells you the project has to deal with resumes written for earlier versions of itself. If you are coming from an older copy of the tool, that migration path exists, and the icons themselves come from Iconify with a search interface at Icons, so adding an icon is a copy-paste rather than a design task.

## Self-hosting it, and the four environment variables

The project can be hosted on your own infrastructure, and the steps are short.

Clone the repository, optionally copy the environment example, run the build script, and deploy the output directory to any static hosting provider, with GitHub Pages, Netlify, Vercel and Nginx named.

The environment file lives in the site folder and starts as site/.env.example:

```bash
cp site/.env.example site/.env
```

Four variables are documented, and all four are optional in effect. NUXT_PUBLIC_GOOGLE_FONTS_KEY is the Google Fonts Developer API key, required to enable the font picker that lists fonts from Google Fonts, and without it the font selection shows only locally available fonts. NUXT_PUBLIC_GTAG_ID is a Google Analytics 4 measurement ID, and leaving it empty disables analytics. NUXT_CLARITY_ID is a Microsoft Clarity project ID for session recording and heatmaps, empty to disable. NUXT_PUBLIC_DISQUS_SHORTNAME enables the Disqus comment section, empty to hide comments.

That is a well-thought-out set of defaults for a self-hosted tool. Someone running their own instance of a privacy-friendly resume editor probably does not want their visitors' sessions recorded by a third party, and each of these can simply be left unset.

For development, the package manager is pnpm, the workspace has separate packages and a site, and the scripts are pnpm install, pnpm run build:pkg for the packages, and pnpm run dev and pnpm run build for the site.

## AGPL-3.0 and a one-version release history

The licence is AGPL-3.0, and the repository points to a LICENSE file and an ACKNOWLEDGMENTS file for credits.

That is worth pausing on for a project whose whole pitch is privacy and local-first hosting. The AGPL is the strongest copyleft in common use, and its network clause is the part that matters for a self-hostable web app. If you run a modified instance of this as a network service for other people, the AGPL's terms reach further than a permissive licence would. No legal advice is offered here beyond naming the identifier, but a team that plans to deploy a modified version for colleagues should read the licence text rather than assume the MIT-style expectations that come with most personal tools.

The release history is thin. There is one tagged release, v2026.07.08 from 2026-07-09, and the repository is not archived with the last push on 2026-09-20. The version scheme is a date, which tells you the project versions itself by release day rather than by semver, so pinning is a matter of choosing a date tag.

The changelog is pointed at for the complete project history, and the root package.json version is 0.1.1 while the published site version is the dated one, so the two version lines are separate things and the date tag is the one that identifies a deployable release.

## Conclusion

markdown-resume is a good fit for a developer who wants a resume as a text file in version control and does not want a web form uploading their career history to a server, because the storage is IndexedDB in your own browser and the export targets are the ones recruiters and ATS parsers actually read. It is a poor fit for someone who needs their resumes on a phone and a laptop at the same time, because there is no account and no sync, and a poor fit if you need a design-heavy multi-column layout, because the template is deliberately restrained. Before adopting, export one resume to PDF and DOCX and check the pagination yourself, since the automatic page breaking is the feature most likely to need adjusting, and read the changelog if you have an older version, because the project states it can migrate legacy Iconify markup from older resumes.

## FAQ

### Does markdown-resume upload my resume data anywhere?

No. The project describes itself as local-first, and resumes, images and settings stay in your browser with no account required. Storage uses IndexedDB through localForage, and the README states your resume content is not uploaded to an application server.

### What formats can markdown-resume export to?

PDF, Markdown, self-contained HTML and DOCX, with A4 and US Letter paper sizes. When exporting to HTML or DOCX, image references are replaced with inline base64 data URLs so the file carries its own images.

### How do I add an image to my markdown-resume document?

Upload it in the Image Gallery screen, then copy the URL, which has the form ./images/<id> and is served by a Service Worker, into your Markdown as an image tag or into an HTML img tag. The images are stored in the same browser IndexedDB as your resumes.

### How do I self-host markdown-resume?

Clone the repository, optionally copy site/.env.example to site/.env, run ./build.sh, and deploy the contents of the .output/public directory to any static hosting provider such as GitHub Pages, Netlify, Vercel or Nginx.

## Sources

- [junian/markdown-resume on GitHub](https://github.com/junian/markdown-resume)
- [License: AGPL-3.0](https://github.com/junian/markdown-resume/blob/master/LICENSE)
- [Project website](https://www.junian.dev/markdown-resume/)
- [README](https://github.com/junian/markdown-resume/blob/master/README.md)
- [Releases](https://github.com/junian/markdown-resume/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/junian-markdown-resume
