Migration Guide¶
Migration from v3¶
v4 has a profile-based architecture. Each CV variant is in its own profile_<name>/ directory, with a self-contained metadata.toml and its content modules. This corrects #142. You can now change any field for each profile, which includes [personal.info], [layout], and [inject]. v3 supported only the three localized strings in [lang.<code>].
Design principles¶
- One profile is one complete CV configuration. A single
profile_<name>/metadata.tomlshows the full effective configuration for that profile. There is no merge and no inheritance. - No root
metadata.toml. The v4 template contains only profile directories. There is no shared base configuration layer. - DRY is the work of the user, not of the package. To share configuration between many profiles, you can add your own preprocessor or symlinks. The package stays simple.
Upgrade steps¶
1. Rename your module directory to a profile directory:
2. Move your metadata.toml into the profile directory and flatten the schema:
You must also flatten the v3 [lang.<code>] structure to top-level fields. When v4 finds a v3-only schema field, it panics. This is the same behavior as the v2 to v3 inject_* migration guards. For the exact field mapping, see "Schema migration guards".
3. Update your cv.typ:
// Before (v3)
#import "@preview/brilliant-cv:3.3.0": cv
#let metadata = toml("./metadata.toml")
#let cv-language = sys.inputs.at("language", default: none)
#let metadata = if cv-language != none {
metadata + (language: cv-language)
} else {
metadata
}
#let import-modules(modules, lang: metadata.language) = {
for module in modules {
include { "modules_" + lang + "/" + module + ".typ" }
}
}
// After (v4) — profile-based, no merge
// release-current-version
#import "@preview/brilliant-cv:4.1.0": cv
#let profile = sys.inputs.at("profile", default: "en")
#let metadata = toml("profile_" + profile + "/metadata.toml")
#let import-modules(modules) = {
for module in modules {
include { "profile_" + profile + "/" + module + ".typ" }
}
}
4. Update letter.typ — same preamble pattern.
5. Update CLI commands:
6. Add more profiles. Copy profile_en/ to profile_<new>/. Then edit the fields that are different. Each profile is independent. The package has no DRY mechanism, and this is intentional.
See Recipes → Switching Profiles for compile-time examples.
Schema migration guards (panic on v3 fields)¶
v4 uses the same pattern as the v2 to v3 migration of inject_ai_prompt and inject_keywords. When the package finds a removed v3 schema field at compile time, it panics with a migration message. It does not fall back silently. A silent fallback is an anti-pattern, because it hides a change of behavior.
The guarded fields and their replacements:
| v3 field | Panic? | v4 replacement |
|---|---|---|
language |
✅ | Set typography explicitly: [layout.fonts] regular_fonts, [layout.fonts] header_font, [layout.section] title_highlight, [personal] display_name, [layout] date_width |
non_latin_font |
✅ | List both fonts in [layout.fonts] regular_fonts = ["Source Sans 3", "Heiti SC"] and set [layout.fonts] header_font. Typst selects the font for each codepoint, so mixed scripts work. A test with pdffonts shows the same embedded subsets as the v3 trigger. |
non_latin_name |
✅ | [personal] display_name. It replaces the Latin split of first name and last name with one styled string. |
[lang.<code>] table |
✅ | Set header_quote, cv_footer, letter_footer as top-level fields in profile_<name>/metadata.toml |
[lang.non_latin] table |
✅ (the [lang.*] panic in the previous row covers it) |
Use [personal] display_name and [layout.fonts] |
v3 (language=zh) → v4 example¶
Before:
language = "zh"
non_latin_font = "Heiti SC"
non_latin_name = "王道尔"
[lang.zh]
header_quote = "具有丰富经验的数据分析师,随时可入职"
cv_footer = "简历"
letter_footer = "申请信"
After:
header_quote = "具有丰富经验的数据分析师,随时可入职"
cv_footer = "简历"
letter_footer = "申请信"
[layout]
date_width = "4.7cm"
[layout.fonts]
regular_fonts = ["Source Sans 3", "Heiti SC"]
header_font = "Heiti SC"
[layout.section]
title_highlight = "full"
[personal]
display_name = "王道尔"
v4 removes the file src/utils/lang.typ, with its _is-non-latin() whitelist and its _default-date-width() lookup table. A new non-Latin script (Arabic, Hebrew, Thai, Devanagari, and more) no longer needs a change to the package. Users configure the typography directly.
Why panic instead of silent fallback?¶
The package has three patterns for backward compatibility. For schema changes, v4 uses panic with a migration message:
| Pattern | When used | Example |
|---|---|---|
| Panic with migration message | Removed metadata schema fields | inject_ai_prompt, v3 language / non_latin_* / [lang.*] |
| Fully removed | Renamed function/parameter aliases | cvEntry, profilePhoto, awesomeColors (typst gives a generic "unknown parameter" error) |
| Silent fallback | ❌ Not used in v4. v3 metadata fields used it for a short time. v4 removed it, because a hidden change of behavior broke the "explicit > implicit" design. |
Removed in v4 (no longer panic — fully removed)¶
These parameter aliases and function aliases panicked in v3. v4 removes them completely. Code that still uses them fails with a generic "unknown parameter" or "unknown function" error, not with the v3 deprecation panic.
Parameter aliases (now removed):
| Removed name | Use instead |
|---|---|
profilePhoto (in cv()) |
profile-photo |
myAddress (in letter()) |
sender-address |
recipientName (in letter()) |
recipient-name |
recipientAddress (in letter()) |
recipient-address |
awesomeColors (in entry/section/honor) |
awesome-colors |
refStyle (in cv-publication) |
ref-style |
refFull (in cv-publication) |
ref-full |
keyList (in cv-publication) |
key-list |
Function aliases (now removed):
cvEntry, cvEntryStart, cvEntryContinued, cvSection, cvSkill, cvSkillWithLevel, cvSkillTag, cvHonor, cvPublication, and hBar. Use the kebab-case names.
Schema migration guards kept: if metadata.toml contains inject_ai_prompt or inject_keywords, the package still panics with a clear upgrade message. A silent ignore of an unknown metadata key is confusing. A user whose ATS keywords disappear must know the cause.
Supported root exports in v4¶
The supported package-root API consists of cv, letter, cv-section, cv-entry, cv-entry-start, cv-entry-continued, cv-skill, cv-skill-with-level, cv-skill-tag, cv-honor, cv-publication, h-bar, and overwrite-fonts.
overwrite-fonts stays in the API for v4 compatibility, because older wildcard imports made it reachable. In a new template, configure [layout.fonts] and let cv() or letter() resolve the fonts. A new decision about this helper belongs in v5.
Older releases also made dependency symbols available through wildcard imports, such as the fa-* icons and the internal state. These symbols were never documented compatibility commitments, and the package no longer re-exports them. Import the icons from Font Awesome directly:
Migration from v2¶
v3 has a new directory structure and kebab-case names. It also removes several deprecated features. If you upgrade from v2, do these steps.
1. Update Imports¶
The package entry point does not change. Update each version-pinned import:
// Before (v2)
#import "@preview/brilliant-cv:2.3.0": *
// After (v3)
#import "@preview/brilliant-cv:3.3.0": *
2. Parameter Renaming (now panics)¶
In v3, all camelCase parameter aliases panic at compile time. They do not map silently to the new names. Update every call site:
| Old (v2, camelCase) | New (v3, kebab-case) | Function |
|---|---|---|
profilePhoto |
profile-photo |
cv() |
myAddress |
sender-address |
letter() |
recipientName |
recipient-name |
letter() |
recipientAddress |
recipient-address |
letter() |
awesomeColors |
awesome-colors |
cv-section, cv-entry, cv-honor, and more |
refStyle |
ref-style |
cv-publication |
refFull |
ref-full |
cv-publication |
keyList |
key-list |
cv-publication |
3. Removed Function Aliases (now panic)¶
The old camelCase function names now panic immediately. Rename every use:
| Old (v2) | New (v3) |
|---|---|
cvEntry |
cv-entry |
cvEntryStart |
cv-entry-start |
cvEntryContinued |
cv-entry-continued |
cvSection |
cv-section |
cvSkill |
cv-skill |
cvSkillWithLevel |
cv-skill-with-level |
cvSkillTag |
cv-skill-tag |
cvHonor |
cv-honor |
cvPublication |
cv-publication |
hBar |
h-bar |
4. Removed [inject] Keys (now panic)¶
v3 removes the old injection keys. If your metadata.toml still contains them, the CV panics:
# Before (v2) — these now cause panics
[inject]
inject_ai_prompt = true
inject_keywords = true
injected_keywords_list = ["Python", "SQL"]
# After (v3) — just use the list directly; remove the boolean flags
[inject]
injected_keywords_list = ["Python", "SQL"]
# custom_ai_prompt_text = "Optional custom prompt"
inject_keywordsis removed. Ifinjected_keywords_listis present, the package injects the keywords automatically.inject_ai_promptis removed. Usecustom_ai_prompt_text.
5. Template Updates¶
If you use the template, update cv.typ and letter.typ with the new parameter names. For the current signatures, see the API Reference.
Migration from v1¶
Note
Version v1 is deprecated, because the package now obeys the Typst Packages standard. To continue work on the older version, use the v1-legacy branch.
An existing CV project that uses v1 needs a migration. You must replace some files, and some content in other files.
-
Remove the old submodule — Remove the
brilliant-CVdirectory and.gitmodules. Typst now does the package management. -
Migrate the metadata — Create a new
metadata.tomland move all the configuration frommetadata.typinto it. Use the example TOML file in the repository as a model. -
Update the entry points — Copy the new
cv.typandletter.typfrom the repository. Then adapt them to the modules in your project. -
Update module files in
modules_*/:- Remove the old import
#import "../brilliant-CV/template.typ": *. Replace it with the import statements from the new template files. - Typst changed its path handling, so some functions no longer accept a path string. This applies to the
logoargument incv-entryand tocv-publication. Some parameter names also changed. Pass a function, not a string. For example, useimage("logo.png")in place of"logo.png". For more information, see the new template files.
- Remove the old import
-
Install the fonts — You can need
FontAwesome 6,Roboto, andSource Sans Proon your local system. The new Typst package guidelines are against the inclusion of these large files in a package. -
Compile — Run
typst compile cv.typ. Do not use thefont-pathflag. The migration is then complete.
Tip
If you have a problem that you cannot solve, raise an issue.