Recipes¶
Adding a New Module¶
- Create a new file, e.g.
profile_en/volunteering.typ - Add your imports and content (sections, entries, etc.)
- In
cv.typ, add"volunteering"to theimport-modulescall
Switching Profiles at Compile Time¶
The profile input picks which profile_<name>/ directory to load. For non-Latin scripts (Chinese, Japanese, Korean, Russian, Arabic, …), configure typography explicitly in [layout.fonts] (font fallback chain), [layout.section] (title highlighting), and [personal] display_name. See template/profile_zh/metadata.toml for a complete example.
Adding a New Profile¶
Each profile is self-contained — one profile_<name>/metadata.toml holds the complete CV configuration for that variant. To add a new profile (e.g. a Swedish CV):
- Copy an existing profile directory:
- Edit
profile_swe/metadata.toml— changeheader_quote,cv_footer,letter_footer, and any other fields that differ from English. - Edit the
.typmodules underprofile_swe/for Swedish content. - Compile with
typst compile cv.typ --input profile=swe.
There is no shared root metadata or merge mechanism in v4. Profile = a complete CV config; copy-paste is the way to start a new one.
Profile ≠ language¶
The profile name is just a directory suffix — it doesn't carry semantic meaning to the package. You can have profile_us/ and profile_uk/ (both English text, different locations / phone numbers / layouts) sitting next to profile_zh/ (Chinese with Heiti SC); each profile's metadata.toml is independently complete. Pick whatever directory names make sense for your variants.
Sharing config across profiles¶
If you maintain many profiles and want to share fields (GitHub username, layout colors, etc.), the package itself does not provide a merge mechanism. Common user-side options:
- A small Python/shell preprocessor that reads a canonical base + per-profile overrides and writes the profile
metadata.tomlfiles at build time. typstyle-friendly hand-edits — for 2-3 profiles, manual sync is usually fine.- Symlinks or
git rerereto keep selected fields in sync.
The framework keeps "one profile = one file" so your tooling stays free.
Skills with Inline Separators¶
Use #h-bar() to separate skill items within cv-skill:
Verification Links and Richer Certificate Metadata¶
cv-honor is intentionally compact: it ships with date, title, issuer, url, and location — no free-form description slot. Pick the right component based on what you need to surface.
Just a clickable verification link — pass the verification URL as url. The title becomes a link; location is a good place for short status text:
#cv-honor(
date: [2025],
title: [AWS Certified Solutions Architect],
issuer: [Amazon Web Services],
url: "https://www.credly.com/badges/<your-badge-id>",
location: [Verified],
)
Credential ID, expiry, multiple links — switch to cv-entry, which has a content-flexible description field. The trade-off is a slightly heavier visual footprint, but you get full formatting freedom:
#cv-entry(
title: [AWS Certified Solutions Architect],
society: [Amazon Web Services],
date: [2025 -- 2028],
location: [Verified],
description: list(
[Credential ID: ABC-123-XYZ],
[#link("https://verify.example.com")[Verify online]],
),
)
The two components are interchangeable inside a Certificates section; mix them per entry depending on whether you need the compact one-line layout or the richer description block.
Adding a Profile Photo¶
The profile photo is passed as an argument to cv() in your cv.typ, not set in metadata.toml:
Control the shape with profile_photo_radius in [layout.header]:
"50%"— circle (default)"0%"— square"10%"— rounded corners
Set display_profile_photo = false in [layout.header] to hide the photo entirely.
Custom Contact Icon with Image¶
To add a custom contact entry with an image icon (instead of a Font Awesome icon):
-
Define the entry in
metadata.tomlwith anawesomeIconfallback: -
Pass the image in
cv.typvia thecustom-iconsparameter (the key must matchcustom-1):
When a custom-icons entry is provided, it takes priority over the awesomeIcon value from TOML.
Color Customization¶
Preset Colors¶
Set awesome_color in [layout] to one of the built-in presets:
| Name | Hex |
|---|---|
skyblue |
#0395DE |
red |
#DC3522 |
nephritis |
#27AE60 |
concrete |
#95A5A6 |
darknight |
#131A28 |
Custom Hex Color¶
Pass any hex color string directly:
Cover Letter with Signature¶
Create a cover letter with a signature image at the bottom:
#import "@preview/brilliant-cv:4.0.1": letter
#let metadata = toml("metadata.toml")
#show: letter.with(
metadata,
sender-address: "123 Main Street, City, State 12345",
recipient-name: "ABC Company",
recipient-address: "456 Business Ave, City, State 67890",
date: datetime.today().display(),
subject: "Application for Data Analyst Position",
signature: image("assets/signature.png"),
)
Dear Hiring Manager,
// Your letter content here...
Sincerely,
Leave signature as "" (default) to omit the signature image.
CI/CD with GitHub Actions¶
A minimal workflow to compile your CV on every push:
name: Build CV
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Typst
uses: typst-community/setup-typst@v4
- name: Compile CV
run: typst compile cv.typ cv.pdf
- name: Upload PDF
uses: actions/upload-artifact@v4
with:
name: cv
path: cv.pdf
Tip
If your CV uses custom fonts, add a step to install them before compiling. See the Troubleshooting page for font issues.