Find Keys Your Code No Longer Uses
StringLane reads your source and shows where each key is called, plus a filter for the ones nothing calls. What the scan can see, the four ways a live key lands in that list, and why not scanned is different from nothing found.
Last updated
Every project accumulates them. A screen is redesigned, a feature is cut, a key is renamed and the old one stays behind — still translated into every language you support, still counted in your completion percentage, still sent to your AI provider on the next run.
StringLane reads your source code after a project opens and answers two questions: where is this key called, and which keys are called nowhere.
Where one key is used#
The detail pane shows it under the key name.

Used in N places, then the file and line of each call site. Past the first ten, Show all opens the rest.
When nothing calls it, the pane says so — and says what that does and does not mean:

That caveat sits beside the finding rather than in this page, because it is the finding people act on.
Filtering the sidebar to unused keys#
Open the filter popover in the key sidebar and turn on Show only unused.

The line under the toggle is the important one. It says how many source files the answer is based on, so you can tell an answer from an absence of one.

An Unused chip stays visible while the filter is on, with the count beside it, so a filtered list is never mistaken for the whole project.
Not scanned is not the same as nothing found#
A project StringLane has not read yet says not scanned — never "used in 0 places".
Those two look identical in a list and mean opposite things, and only one of them is a reason to delete something. If StringLane read no source files at all, or read them and recognised no keys in them, it tells you that and reports nothing as unused rather than reporting everything.
The scan starts after your project opens, not before, so it never delays the editor.
What the scan can see#
Four ways a key can be live and still appear in the unused list:
- its name is built at runtime —
t('errors.' + code)is invisible to any scanner; - it is called through a wrapper StringLane does not recognise;
- it is named only in a file type the scan does not read;
- it is read directly out of the locale file by the platform, which is how iOS
InfoPlist.stringsand some Android resources work.
A common Flutter case worth knowing: final l10n = AppLocalizations.of(context)! followed by l10n.homeTitle assigns to a local variable, and the scan sees the assignment rather than the key. Those keys report as unused.
Silencing a key that is built at runtime#
For a key you have checked and know is live, the panel has a decision rather than a dismissal. Open Key Metadata for it and tick Called dynamically, under Code usage. The key stops being reported as unused, and the detail pane says Not reported as unused in place of the usual note, so a later session does not re-litigate a question you have already answered.
It is a record in your repository, not a local preference: x-dynamic-key in the @key block on ARB, and in .stringlane/metadata.yaml on the other four formats. That means it is committed, it applies to everyone on the team, and stringlane scan and stringlane check honour it too, because both read the same metadata. Unticking it drops the field rather than recording a false.
For a whole family of runtime-built keys, a pattern is the better tool: see ignore patterns in the CLI, which stringlane.yaml carries for both surfaces.
Before you delete anything#
- Search for the key yourself, including any runtime spelling that differs from the one shown.
- Never delete keys in the same change as anything else. A deletion that turns out to be wrong needs to be revertible on its own.
The same answer is available outside the app: stringlane scan from a terminal, and the read_key_usage tool for a coding agent. See Unused keys in the CLI.
Frequently asked questions
- How do I find unused translation keys in StringLane?
- Open the filter popover in the key sidebar and turn on Show only unused. The list narrows to keys no call site in your source code names, and an Unused chip stays visible so you always know the list is filtered. Treat it as a starting point for a search rather than a delete queue.
- Is a key StringLane reports as unused safe to delete?
- Not on its own. Not referenced means no call site was found, not that the key is dead. A key whose name is built at runtime, called through a wrapper StringLane does not recognise, named only in a file type it does not read, or read straight out of the locale file by the platform will appear in that list and still be live. Search for it before deleting, and never delete keys in the same change as anything else.
How to Turn Off Usage Analytics