Every "free" CV builder I tried had a catch: a paywall, a watermark, or forced account creation. So I built CVFREE — a completely free, open-source CV builder that runs entirely in your browser.
No signup. No backend. No tracking. No watermark.
What it does
- 10 professional templates — clean, ATS-friendly designs
- 5 languages — English, Korean, Japanese, Chinese (Simplified), Spanish
- Real-time preview — WYSIWYG editing
- PDF export — zero branding, clean output
- Privacy-first — all data stays in localStorage/IndexedDB
The zero-backend architecture
The entire app is a static site deployed on Cloudflare Pages. Here's how I handled the common "you need a backend for that" problems:
Persistence → localStorage + IndexedDB
No user accounts means no server-side storage. I use localStorage for the active document metadata and IndexedDB for storing multiple CV drafts. This gives users the "save and come back" experience without ever touching a server.
// Simplified: save current document to IndexedDB
async function saveDocument(doc: CVDocument): Promise<void> {
const db = await openDB('cvfree', 1, {
upgrade(db) {
db.createObjectStore('documents', { keyPath: 'id' });
},
});
await db.put('documents', doc);
}
PDF Export → Client-side rendering
Instead of using a server-side headless browser for PDF generation, I render templates as React components and use the browser's native print API (window.print()) with carefully crafted @media print CSS. This produces pixel-perfect PDFs with zero server cost.
Template System → Component-driven
Each template is a React component implementing a shared interface:
interface TemplateProps {
data: CVData;
theme: ThemeConfig;
}
interface TemplateMeta {
id: string;
name: string;
component: React.FC<TemplateProps>;
thumbnail: string;
}
Adding a new template is literally one file: create the component, register it in the template registry, done.
Internationalization → next-intl
Full i18n with locale-prefixed routing (/en, /ko, /ja, etc.). The CV content itself is also localized — section headers, date formats, and suggested text adapt to the selected language.
Tech Stack
| Layer | Choice | Why |
|---|---|---|
| Framework | Next.js 14 (App Router) | File-based routing, RSC |
| Styling | Tailwind CSS | Utility-first, fast iteration |
| State | Zustand | Lightweight, no boilerplate |
| i18n | next-intl | Clean API, SSR-compatible |
| Hosting | Cloudflare Pages | Free tier, global CDN |
| Analytics | None | Privacy-first by design |
What I learned
Print CSS is powerful — You can achieve professional PDF output with just
@media print,page-break-*properties, and precisemmunits. No headless browser needed.IndexedDB > localStorage for documents — localStorage has a 5MB limit and synchronous API. IndexedDB handles large documents asynchronously and supports much larger storage.
Zero backend = zero operating cost — The entire project runs on Cloudflare's free tier. No database, no API server, no maintenance overhead.
Templates as pure components — Separating data schema from presentation makes adding templates trivial. The hardest part is designing good-looking templates, not wiring them up.
Try it
Visit cvfree.pages.dev — no account needed. Just start typing.
I'd love feedback on the template designs, PDF quality, or any languages you'd want added!

Top comments (0)