Deprecating and retiring message keys
Translation keys accumulate over time. A feature ships, its onboarding flow is replaced six months later, and the original messages remain - referenced nowhere in the application, but still authoring overhead and still appearing in every datafile build. At scale this creates real friction: build output is larger than it needs to be, the catalog is harder to navigate, and new engineers cannot tell which messages are still in use.
Messagevisor gives you two tools for handling this lifecycle: deprecated for signaling keys that should be removed from application code, and archived for removing them from runtime artifacts entirely.
The two-phase retirement workflow#
Deleting a message key immediately is risky if the application still references it in code. The SDK falls back gracefully on missing keys, but a sudden absence of a string in a UI is still a user-visible problem. A safer pattern is to use a grace period:
- Mark the message
deprecated: truewith an explanatorydeprecationWarning. - Let the SDK surface the deprecation warning in application logs so engineers can find all call sites.
- Once all call sites are removed from the application code, mark the message
archived: true. - Archived messages are excluded from build output and invisible to the runtime.
Marking a message as deprecated#
description: Original onboarding welcome heading, replaced by onboarding.introdeprecated: truedeprecationWarning: Use onboarding.intro instead. This key will be removed after 2026-06-01.translations: en: Welcome to the product nl: Welkom bij het productThe deprecated and deprecationWarning fields are included in the built datafile. The JavaScript SDK emits a deprecated_message warning diagnostic at runtime whenever the deprecated message is evaluated. Engineers running the application locally will see it in their console before any user is affected.
The message still resolves - deprecated does not break anything. It is a signal, not a removal.
Handling the SDK diagnostic#
The SDK reports diagnostics that pass the configured logLevel. By default, logLevel is "info", so diagnostics are written to the console with a [Messagevisor] prefix unless you provide onDiagnostic. Use onDiagnostic when you want to route SDK diagnostics to your own observability pipeline:
import { createMessagevisor } from "@messagevisor/sdk";const m = createMessagevisor({ datafile, locale: "en-US", context: { platform: "web" }, onDiagnostic: (diagnostic) => { if (diagnostic.code !== "deprecated_message") { return; } logger.warn("[messagevisor]", diagnostic.deprecationWarning, diagnostic); datadogRum.addError(new Error(diagnostic.deprecationWarning || diagnostic.message)); },});This gives you a way to identify and track deprecated message call sites in production without requiring engineers to manually audit all call sites. The diagnostic includes messageKey, locale, and deprecationWarning. Set logLevel: "warn" when you only want warnings and errors in the console, or logLevel: "debug" in local development when you also want to inspect override matching decisions.
Archiving a message after all call sites are removed#
Once no part of the application references onboarding.welcome any more, remove it from runtime artifacts by archiving it:
description: Original onboarding welcome heading, replaced by onboarding.introarchived: truetranslations: en: Welcome to the product nl: Welkom bij het productArchived messages are:
- excluded from build output
- excluded from CSV exports
- excluded from the catalog browsable message list
- excluded from lint checks that require translations to be present
The YAML file remains in the repository for Git history purposes. If you want to fully remove the key, delete the file and commit the deletion.
Deprecating and archiving with sets#
In a sets-based project, deprecation and archiving can be applied per set. A message that is deprecated in dev and staging but still active in production gives teams time to clear up application code without forcing immediate retirement from the production artifact.
deprecated: truedeprecationWarning: Use onboarding.intro instead.translations: en: Welcome to the producttranslations: en: Welcome to the productWhen you are confident all call sites are cleared across all applications, archive the message in all sets:
$ npx messagevisor build --set=production --showSizeArchiving the message and rebuilding will make the datafile smaller. The --showSize flag lets you confirm that the removal had the expected effect.
Avoiding accidental promotion of deprecated messages#
If you use sets-based promotion and a deprecated message should not propagate further, set promotable: false on it:
deprecated: truepromotable: falsedeprecationWarning: Use onboarding.intro instead.translations: en: Welcome to the productThis prevents promote --from=staging --to=production from overwriting a production message you may have already cleaned up.
Testing that deprecated messages still resolve during the grace period#
During the grace period, deprecated messages should still pass their existing translation assertions. Do not remove tests while the message is only deprecated rather than archived.
message: onboarding.welcomeassertions: - description: Still resolves during deprecation grace period locale: en target: web expectedTranslation: Welcome to the productOnce the message is archived, remove the test file. Running npx messagevisor test against an archived message will behave as though the message does not exist, which is expected.
Testing that archived messages are absent from targets#
After archiving, write a target test to assert that the message has been removed from the built artifact:
target: webassertions: - description: Archived onboarding welcome is not included expectedToNotIncludeMessages: - onboarding.welcomeThis provides an explicit regression gate against accidentally unarchiving a message through a promotion.
Bulk deprecation review with the catalog#
The catalog shows deprecated and archived status on message rows. If you want to audit all deprecated messages in a project:
$ npx messagevisor catalog exportThen browse the catalog UI filtered to the namespace of interest, or use the CLI evaluate command with a pattern to spot-check deprecated messages:
$ npx messagevisor evaluate --message=onboarding.welcome --locale=en --target=webChecking for deprecated messages across the project#
To find all deprecated messages in your project before a cleanup sprint, evaluate or inspect the built datafile:
$ npx messagevisor build --target=web --locale=en$ cat datafiles/messagevisor-web-en.json | jq '[.messages | to_entries[] | select(.value.deprecated == true) | .key]'The built datafile includes deprecated: true on each deprecated message. This gives you a machine-readable list you can use to prioritize cleanup work.
Managing grace periods explicitly#
For teams that want formal grace periods tracked in the definition itself, use meta to record the deadline:
description: Original onboarding welcome heading, replaced by onboarding.introdeprecated: truedeprecationWarning: Use onboarding.intro instead.meta: deprecatedAt: "2025-10-01" removeAfter: "2026-06-01" removalTrackedIn: "JIRA-4892"translations: en: Welcome to the product nl: Welkom bij het productThe meta fields are included in the built datafile and visible in the catalog. Engineers running the application can read the removeAfter date with getMessageMeta(), and you can build automation that alerts when a message is past its removeAfter deadline but still active.
Summary of the lifecycle#
| State | In build output | SDK evaluates | SDK warns | CLI lists |
|---|---|---|---|---|
| Active | Yes | Yes | No | Yes |
| Deprecated | Yes | Yes | Yes | Yes |
| Archived | No | N/A | N/A | No |

