Visualforce is a Salesforce framework for building custom user interfaces that run on the Lightning Platform. A Visualforce page combines tag-based markup with Salesforce data, standard controllers, custom Apex controllers, or controller extensions.

Visualforce remains relevant for maintaining existing Salesforce applications, generating PDF documents, overriding certain standard actions, and supporting interfaces that have not been migrated to Lightning Web Components. For most new interactive Lightning Experience interfaces, Lightning Web Components are generally the preferred option.

How a Visualforce page works in Salesforce

A Visualforce page is stored as metadata in Salesforce. When a user requests the page, Salesforce processes its markup and controller logic on the server, retrieves or updates the required records, and returns the generated HTML to the browser.

  • Visualforce markup: Defines the page structure with components such as <apex:page>, <apex:form>, and <apex:outputField>.
  • Controller: Supplies records, values, and actions to the page. It may be a standard Salesforce controller, a custom Apex class, or both through an extension.
  • Expressions: Bind markup to controller properties and methods using syntax such as {!account.Name}.
  • View state: Preserves component and controller state between applicable server requests.
  • Rendered response: Produces HTML, and optionally other output such as a PDF, for the client.

Create a basic Visualforce page

Developers commonly create and deploy Visualforce metadata with Salesforce development tools. In an org where Visualforce page creation is available in Setup, you can also locate Visualforce Pages, select New, enter a label and name, add the markup, and save the page.

The following page displays a heading and text without using an Apex controller:

</>
Copy
<apex:page>
    <apex:pageBlock title="Visualforce Example">
        <apex:pageBlockSection>
            <apex:outputText value="This page is rendered by Visualforce." />
        </apex:pageBlockSection>
    </apex:pageBlock>
</apex:page>

The root <apex:page> component identifies the file as a Visualforce page. The nested components create a titled container, a section, and a text value.

Display Salesforce records with a standard controller

A standard controller provides built-in record operations for a Salesforce object. This approach can display and edit a record without requiring a custom Apex controller.

</>
Copy
<apex:page standardController="Account">
    <apex:pageBlock title="Account Details">
        <apex:pageBlockSection columns="1">
            <apex:outputField value="{!Account.Name}" />
            <apex:outputField value="{!Account.Industry}" />
            <apex:outputField value="{!Account.Phone}" />
        </apex:pageBlockSection>
    </apex:pageBlock>
</apex:page>

Open a record-specific page by passing an Account record ID in the URL, for example /apex/AccountDetails?id=001.... The standard controller uses that ID to load the record. The user must have permission to access both the page and the requested data.

Build an editable Visualforce form

Place input fields and command components inside <apex:form> when the page must submit values to the server. The standard controller supplies actions such as save and cancel.

</>
Copy
<apex:page standardController="Contact">
    <apex:form>
        <apex:pageBlock title="Edit Contact">
            <apex:pageMessages />
            <apex:pageBlockSection columns="1">
                <apex:inputField value="{!Contact.FirstName}" />
                <apex:inputField value="{!Contact.LastName}" />
                <apex:inputField value="{!Contact.Email}" />
            </apex:pageBlockSection>
            <apex:pageBlockButtons>
                <apex:commandButton value="Save" action="{!save}" />
                <apex:commandButton value="Cancel" action="{!cancel}" />
            </apex:pageBlockButtons>
        </apex:pageBlock>
    </apex:form>
</apex:page>

<apex:pageMessages> displays validation errors and other messages returned during submission. Using field components such as <apex:inputField> also allows Salesforce to apply object metadata to the rendered control.

Use a custom Apex controller with Visualforce

A custom controller is useful when the page requires queries, calculations, navigation, or actions that a standard controller does not provide. Public properties and methods referenced by the page must be accessible to Visualforce.

</>
Copy
public with sharing class RecentAccountsController {
    public List<Account> accounts { get; private set; }

    public RecentAccountsController() {
        accounts = [
            SELECT Id, Name, Industry, Phone
            FROM Account
            ORDER BY CreatedDate DESC
            LIMIT 10
        ];
    }
}

The corresponding Visualforce page binds an iteration component to the accounts property:

</>
Copy
<apex:page controller="RecentAccountsController">
    <apex:pageBlock title="Recently Created Accounts">
        <apex:pageBlockTable value="{!accounts}" var="account">
            <apex:column value="{!account.Name}" />
            <apex:column value="{!account.Industry}" />
            <apex:column value="{!account.Phone}" />
        </apex:pageBlockTable>
    </apex:pageBlock>
</apex:page>

The with sharing declaration applies the current user’s record-sharing rules to queries performed by this controller. Developers must also deliberately enforce relevant object-level and field-level permissions in custom Apex code.

Extend a standard controller with Apex

A controller extension retains standard controller behavior while adding custom properties or actions. Its constructor receives an ApexPages.StandardController instance.

</>
Copy
public with sharing class AccountPageExtension {
    private final Account currentAccount;

    public AccountPageExtension(ApexPages.StandardController controller) {
        currentAccount = (Account) controller.getRecord();
    }

    public String getDisplayMessage() {
        return 'Viewing account: ' + currentAccount.Name;
    }
}
</>
Copy
<apex:page standardController="Account"
           extensions="AccountPageExtension">
    <apex:pageMessages />
    <apex:outputText value="{!displayMessage}" />
</apex:page>

This pattern is suitable when a page needs standard record handling plus a limited amount of custom logic.

Visualforce expressions and component attributes

Visualforce expressions use {! ... } delimiters. They can read controller properties, call getter methods, execute action methods from supported components, and evaluate formula-style expressions.

</>
Copy
<apex:outputText value="{!Account.Name}" />
<apex:outputText value="{!IF(Account.Active__c, 'Active', 'Inactive')}" />
<apex:commandButton value="Save" action="{!save}" />
<apex:outputPanel rendered="{!NOT(ISBLANK(Account.Phone))}">
    <apex:outputText value="{!Account.Phone}" />
</apex:outputPanel>

The meaning of an expression depends on the component attribute. A value attribute normally reads data, an action attribute invokes a controller action, and a rendered attribute controls conditional rendering.

Visualforce view state and page performance

Visualforce may maintain serialized page state between server requests. Large controller properties, deeply nested component trees, and unnecessary forms can increase view state and affect response time.

  • Mark controller properties as transient when their values do not need to survive the next request.
  • Query only the fields and records required by the page.
  • Use pagination instead of placing large record collections in one table.
  • Avoid placing the entire page inside a form when only one section submits data.
  • Move static data and calculations out of persistent controller state where practical.
  • Check the page’s view-state information during development when server round trips become slow.

Visualforce security and page access

Access to a Visualforce page does not automatically grant access to every object, field, record, or Apex class used by that page. Review each layer of access before deployment.

  • Grant Visualforce page access through an appropriate profile or permission set.
  • Grant access to any custom Apex controller or extension used by the page.
  • Use with sharing where controller behavior should respect record-sharing rules.
  • Check object permissions and field-level security when custom Apex reads or writes data.
  • Validate untrusted input and use bind variables in SOQL rather than constructing unsafe query strings.
  • Rely on Visualforce’s default output escaping unless trusted content has a specific rendering requirement.
  • Test the page as representative users, not only as a system administrator.

Use Visualforce in Lightning Experience

Visualforce pages can operate in Lightning Experience, but an older page does not automatically acquire Lightning styling or responsive behavior. Test navigation, JavaScript, CSS, record context, mobile layout, and interactions inside the Lightning container.

A Visualforce page can be exposed for supported Lightning uses through its page settings and metadata. When embedding a page, also consider frame boundaries, content security restrictions, and whether the page depends on assumptions from Salesforce Classic.

Visualforce vs Lightning Web Components

RequirementVisualforceLightning Web Components
Rendering modelPrimarily server-rendered pages with Visualforce components and Apex controllersClient-side components based on modern web standards
Existing Salesforce applicationsSuitable for maintaining and extending established Visualforce implementationsMay require migration or integration work
New Lightning interfaceUseful for specific supported cases and existing page-based workflowsUsually the first option for new interactive Lightning UI
PDF generationSupports Visualforce pages rendered as PDF, subject to platform limitationsDoes not provide the same direct Visualforce PDF-rendering model
Interaction patternOften uses server requests, forms, and view stateUses JavaScript, component state, events, and Salesforce data services or Apex

Visualforce is not simply interchangeable with Lightning Web Components. The choice depends on the existing architecture, required platform feature, user experience, maintenance cost, and migration scope. Salesforce provides the Visualforce Developer Guide for framework details and the Lightning Web Components Developer Guide for component-based Lightning development.

Test a Visualforce controller with Apex

Controller tests should create their own data, instantiate the controller or extension, execute its actions, and verify the resulting state. Use Test.setCurrentPage and page parameters when the logic depends on the current Visualforce request.

</>
Copy
@IsTest
private class AccountPageExtensionTest {
    @IsTest
    static void returnsAccountDisplayMessage() {
        Account account = new Account(Name = 'Sample Account');
        insert account;

        Test.setCurrentPage(Page.AccountDetails);
        ApexPages.currentPage().getParameters().put('id', account.Id);

        ApexPages.StandardController standardController =
            new ApexPages.StandardController(account);
        AccountPageExtension extension =
            new AccountPageExtension(standardController);

        System.assertEquals(
            'Viewing account: Sample Account',
            extension.getDisplayMessage()
        );
    }
}

Replace Page.AccountDetails with the generated page reference for the Visualforce page in the org. Add tests for successful actions, validation failures, missing parameters, permission-sensitive behavior, and bulk data where relevant.

Visualforce troubleshooting checks

  • Insufficient privileges: Verify Visualforce page access, Apex class access, object permissions, field permissions, and record sharing.
  • Record not found: Confirm that the URL contains the correct id parameter and that the user can access the record.
  • Unknown property or method: Check the expression name and confirm that the controller exposes a matching public property, getter, or action method.
  • Validation error not visible: Add <apex:pageMessages> or an appropriate message component to the form.
  • Slow postback: Review view-state size, query volume, collection size, and unnecessary rerendering.
  • Different behavior in Lightning: Test container navigation, styling, JavaScript dependencies, frame behavior, and Lightning Experience page settings.

Visualforce tutorial QA checklist

  • Confirm that every Visualforce example has one valid <apex:page> root component.
  • Verify that controller names, property names, and Visualforce expressions match exactly.
  • Confirm that record-based examples explain the required id URL parameter.
  • Check that custom Apex examples address sharing, object permissions, and field-level security.
  • Test form examples with both valid input and validation failures.
  • Verify that Visualforce, Apex class, object, field, and record access are described as separate permission layers.
  • Test Lightning Experience claims and behavior in a current Salesforce environment before publication.
  • Confirm that the Visualforce-versus-LWC guidance distinguishes existing-page maintenance from new Lightning UI development.

Frequently asked questions about Visualforce

What is Visualforce in Salesforce?

Visualforce is a Salesforce framework for creating custom user interfaces with tag-based markup, Salesforce data, and optional Apex controller logic. Its pages are hosted and processed on the Lightning Platform.

Is Visualforce deprecated?

Visualforce continues to be documented and supported for existing and applicable Salesforce use cases. However, Lightning Web Components are generally preferred for new interactive interfaces designed specifically for Lightning Experience. Check current Salesforce release documentation when making a long-term architecture decision.

What is the difference between a Visualforce standard controller and a custom controller?

A standard controller supplies built-in record operations for a Salesforce object. A custom controller is an Apex class written for page-specific behavior. A controller extension adds custom Apex behavior while retaining a standard controller’s capabilities.

Can a Visualforce page run in Lightning Experience?

Yes, Visualforce pages can run in supported Lightning Experience contexts. The page must still be tested for Lightning navigation, styling, responsive layout, JavaScript behavior, security restrictions, and page access.

When should Visualforce be used instead of LWC?

Visualforce may be appropriate for maintaining an existing Visualforce application, supporting a page-based feature already built around Apex controllers, or using a capability such as Visualforce PDF rendering. LWC is usually the better starting point for a new component-based Lightning user interface.