Fix the flutter_gen gen_l10n Import Error in Flutter
You pulled a fresh stable Flutter, ran your app, and now every screen that touches localization is red:
Target of URI doesn't exist: 'package:flutter_gen/gen_l10n/app_localizations.dart'
Undefined name 'AppLocalizations'.
Nothing in your code changed. The import that worked for years suddenly doesn't resolve. This isn't a corrupt cache or a bad pub get — the file it points to genuinely no longer exists, because Flutter stopped generating it. Here's exactly what happened and how to migrate in about five minutes.
Why package:flutter_gen doesn't exist anymore
For years, flutter gen-l10n generated your AppLocalizations class into a synthetic package — a fake package:flutter_gen that Flutter injected into your .dart_tool/package_config.json at build time. The generated file never lived in your lib/ folder; it materialized in the tool's cache, which is why you imported it from a package you never added to pubspec.yaml.
That synthetic-package trick was always a hack. It broke build_runner, confused the analyzer and dart fix, and tripped up plugins. Flutter deprecated it, and starting with the 3.32.0 stable line the tool no longer generates the synthetic package by default — localized messages are written into your real source tree instead. The removal was completed in the following stable release. So the import is dangling because there is no package:flutter_gen to resolve.
The fix is to stop importing from a package that no longer exists and point everything at the real generated file.
The 5-minute migration
Step 1 — Keep generate: true in pubspec.yaml
You still need this flag so the tool runs gen-l10n during builds. Leave it as is:
flutter:
generate: true
If dart fix previously added a flutter_gen: any line to your dependencies, delete it — that dependency doesn't exist on pub.dev and will make things worse.
Step 2 — Set synthetic-package: false and choose an output directory
Open (or create) l10n.yaml at your project root. The key change is flutter synthetic-package false, which tells the tool to write real files. Point arb-dir and output-dir at a normal folder in lib/ — lib/l10n is the conventional choice.
Before (old, synthetic):
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
After (real generated source):
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
output-class: AppLocalizations
synthetic-package: false
output-dir: lib/l10n
With output-dir: lib/l10n, your app_localizations.dart and its per-locale parts (app_localizations_en.dart, app_localizations_es.dart, …) are generated right next to your .arb files. If you'd rather keep generated code separate from source-controlled ARBs, split them:
arb-dir: lib/l10n
output-dir: lib/src/generated/l10n
synthetic-package: false
Tip: generated files under output-dir are build artifacts — add that path to .gitignore if you regenerate on every build, or check them in if you prefer reproducible diffs. Both are valid.
Step 3 — Regenerate
flutter clean
flutter pub get
flutter gen-l10n
After this, confirm the real file exists:
ls lib/l10n/app_localizations.dart
If it's there, the migration worked. If not, re-check that generate: true is under the flutter: key and that template-arb-file names a file that actually exists in arb-dir.
Step 4 — Rewrite every import
This is the part that clears the red squiggles. Swap the dead synthetic import for the real path. Because the file now lives inside your own package, you import it with your app's package name (the name: field in pubspec.yaml) — say your app is named my_app:
Old:
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
New:
import 'package:my_app/l10n/app_localizations.dart';
Relative imports work too (import '../l10n/app_localizations.dart';), but the package: form is stable no matter where the importing file sits.
Find-and-replace across the whole project
Don't hand-edit dozens of files. Replace my_app with your real package name and run one command.
macOS / BSD sed:
grep -rl "package:flutter_gen/gen_l10n/app_localizations.dart" lib test \
| xargs sed -i '' 's#package:flutter_gen/gen_l10n/app_localizations.dart#package:my_app/l10n/app_localizations.dart#g'
Linux / GNU sed:
grep -rl "package:flutter_gen/gen_l10n/app_localizations.dart" lib test \
| xargs sed -i 's#package:flutter_gen/gen_l10n/app_localizations.dart#package:my_app/l10n/app_localizations.dart#g'
Using a custom output-dir like lib/src/generated/l10n? Match the replacement to that path: package:my_app/src/generated/l10n/app_localizations.dart.
Step 5 — Verify the app still wires up correctly
Your MaterialApp doesn't change at all — only where AppLocalizations comes from:
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:my_app/l10n/app_localizations.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: HomeScreen(),
);
}
}
And at the call site:
Text(AppLocalizations.of(context)!.helloWorld);
Run flutter analyze — the Target of URI doesn't exist and Undefined name 'AppLocalizations' errors should be gone.
Common gotchas
- Analyzer still red after regenerating. The IDE indexed the old synthetic package. Restart the Dart Analysis Server (VS Code: Dart: Restart Analysis Server; Android Studio: Invalidate Caches / Restart).
flutter_gen: anyin pubspec. Remove it. It was likely added by an over-eagerdart fixand points at nothing.- CI passes locally but fails on build. Ensure
flutter gen-l10n(or a plainflutter build, which runs it) executes before analysis in your pipeline, and that generated files are either committed or generated in CI. - Multiple output files. Remember gen-l10n emits one file per locale plus the main class. All of them land in
output-dir; you only import the mainapp_localizations.dart.
Keep your ARB files sane while you're in here
Moving to real source files is a good moment to tidy the messages themselves — mismatched placeholders and missing translations across locales are the next thing to bite you. If you'd rather not hand-edit raw JSON, the FlutterLocalisation ARB editor gives you a side-by-side view of every locale, flags missing keys, and validates placeholder syntax before it ever reaches gen-l10n. See pricing for team plans.
The synthetic package is history — once your imports point at real files in lib/l10n, your l10n setup is simpler, plays nicely with the analyzer and build_runner, and won't silently break on the next Flutter upgrade.
Try FlutterLocalisation free and manage your ARB files without touching raw JSON.