Apex Page
Apex Page is the metadata-API name for what most Salesforce users call a Visualforce Page.
Definition
Apex Page is the metadata-API name for what most Salesforce users call a Visualforce Page. The Metadata API type is ApexPage, the file extension is .page, and the matching Apex controller is an ApexClass. The two together (the .page markup and its controller) implement a custom Salesforce-hosted web page that runs inside the platform. Apex Pages were the primary way to build custom UI inside Salesforce from 2008 through roughly 2018, when Lightning Components and Lightning Web Components replaced them as the recommended UI surface. The metadata type still exists, the pages still render, and large enterprise orgs typically retain dozens to hundreds of them through any Lightning migration.
The markup language inside an Apex Page is Visualforce, a JSP-style tag library that includes Salesforce-aware components like apex:pageBlock, apex:repeat, apex:inputField, and apex:commandButton. Components bind to controller properties through expression syntax ({!Account.Name}), which evaluates against the Apex controller class associated with the page. Pages can be standard-controller-driven (use the platform-provided controller for an object), custom-controller-driven (use a developer-written class), or both via a controller extension. Most surviving Apex Pages serve niche use cases that Lightning never quite replaced: PDF generation, email templates, public Sites pages, and tightly customised quote or invoice surfaces.
Where Apex Pages came from and how they fit into modern Salesforce
The Visualforce page model
Each Apex Page is a single .page file with Visualforce markup plus a controller binding. The page is requested at /apex/pageName. The server-side renderer evaluates the markup, calls the controller methods, and returns HTML. The result feels like a server-rendered web page that knows about Salesforce objects, fields, and security. Standard controllers handle CRUD for one object; custom controllers handle anything the developer codes.
Standard, custom, and extension controllers
A standard controller (\"standardController\\=Account\") gives the page automatic access to one record's fields, save and cancel methods, and standard list view behaviour. A custom controller is a developer-written Apex class that the page binds to. An extension is a class that supplements the standard controller with additional methods. Most non-trivial pages use either a custom controller or an extension; standard controllers alone fit only the simplest record-edit screens.
Visualforce components and tag libraries
Visualforce ships hundreds of tags. apex:pageBlock and apex:pageBlockSection provide the look that matches classic Salesforce. apex:inputField, apex:outputField, and apex:inputText handle form inputs. apex:repeat and apex:dataTable iterate over collections. Custom Visualforce components (also stored as ApexComponent metadata) let developers package reusable UI snippets. Lightning Components added a parallel surface in 2014 that ultimately superseded most Visualforce work.
Where Apex Pages are still the right tool
PDF generation through renderAs=\"pdf\" remains the strongest niche; Lightning has no first-class PDF rendering. Email templates of type Visualforce stay common because the alternative (HTML Email Template) lacks dynamic logic. Public-facing Sites pages built before Experience Cloud are often Visualforce. Quote and invoice surfaces that escaped Lightning migration also live on. New Lightning development should not start with Apex Pages, but those existing surfaces frequently remain operational.
Lightning Experience compatibility
Apex Pages can render inside Lightning Experience but display in an iframe through the Visualforce Container. The iframe means clean Lightning navigation, toast notifications, and CSS inheritance need explicit attention. The lightning:container module bridges some of the gap, but most legacy Visualforce pages display with subtle visual mismatches that users tolerate but rarely love.
Security and the running-user context
Apex Pages enforce the running user's profile and permission set permissions for object-level CRUD. Field-level security is partially enforced by apex:inputField and apex:outputField (which respect FLS automatically) but not by direct merge expressions like {!Account.SensitiveField__c}. Sharing is enforced if the controller declares with sharing. Pages that bypass these protections through clever Apex are the source of many Salesforce Security Review findings.
Performance characteristics
Visualforce pages render server-side. Large pages with deeply-nested apex:repeat over thousands of records can hit view-state size limits or governor limits. The platform caps view state at 170 KB. Pages that rely on view state to persist controller variables between postbacks often hit the limit and have to be refactored to use Apex Custom Objects or transient variables.
Modern alternatives
Lightning Web Components (LWC) is the recommended UI framework for new work. Aura Components are the older Lightning UI framework, still supported but no longer the recommended starting point. For pure record edit surfaces, Lightning Record Form and the Dynamic Forms feature often replace Visualforce entirely. For PDFs and email templates, Apex Pages remain practical until Salesforce ships first-class replacements.
How to maintain or modernise an Apex Page
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.
Trust & references
Cross-checked against the following references.
- Visualforce Developer GuideSalesforce Developer Docs
- ApexPage Metadata API ReferenceSalesforce Developer Docs
Straight from the source - Salesforce's reference material on Apex Page.
- Lightning Web Components Developer GuideSalesforce Developer Docs
About the Author
Dipojjal Chakrabarti is a B2C Solution Architect with 29 Salesforce certifications and over 13 years in the Salesforce ecosystem. He runs salesforcedictionary.com to help admins, developers, architects, and cert/interview candidates sharpen their fundamentals. More about Dipojjal.
Test your knowledge
Q1. What is another name for an Apex Page?
Q2. What syntax does an Apex Page use?
Q3. What is the recommended modern alternative to Visualforce for new UI development?
Discussion
Loading discussion…