Maintaining surviving Apex Pages and migrating the ones that can be migrated are two different exercises. Knowing which is which is half the work.
- Inventory existing Apex Pages
Query ApexPage in the Tooling API or use the Setup, Visualforce Pages list. Document each page, its controller, its usage (record button, list button, Site page, email template), and the user audience.
- Classify by complexity and value
Three buckets: leave (PDF rendering, email templates, niche surfaces with no Lightning equivalent), migrate (record-edit pages, dashboards), retire (unused pages or pages duplicating standard functionality).
- For migrations, choose the right Lightning target
Lightning Record Form for simple edits, Dynamic Forms for layout flexibility, custom LWC for complex behaviour. Aura Components are no longer the recommended starting point.
- Maintain surviving pages with discipline
Apex Pages still need governor-limit-aware Apex, view-state hygiene, and FLS-aware merge syntax. Treat them as production code despite their legacy status.
- Retire unused pages aggressively
Old Visualforce pages tend to outlive their use. Audit Setup, Visualforce Pages annually and delete the ones with zero traffic. Each retired page is one fewer maintenance liability.
- Merge syntax like {!Account.SensitiveField__c} does not enforce field-level security automatically. Use apex:outputField or check FLS explicitly in the controller.
- Apex Pages render inside an iframe in Lightning Experience. Inline JavaScript that assumes top-window context breaks; use the postMessage bridge or refactor.
- View state caps at 170 KB. Heavy apex:repeat loops and verbose controller state often hit it. Mark variables transient or move state to custom objects.
- New development should default to LWC. Adding a new Apex Page in 2026 is rarely the right answer outside of PDF and email-template use cases.