Custom Controller
A Custom Controller in Salesforce is an Apex class that provides all the data and behavior for a Visualforce page, without relying on the Standard Controller framework.
Definition
A Custom Controller in Salesforce is an Apex class that provides all the data and behavior for a Visualforce page, without relying on the Standard Controller framework. The page declares the class through the controller attribute, and from that moment on, every getter, setter, and action method called from the page must exist on that class. Custom Controllers give developers complete control over data access patterns, custom queries, complex business logic, and navigation, at the cost of writing more code than a Standard Controller would require.
Custom Controllers exist because Standard Controllers are object-bound and cannot do anything the standard CRUD APIs cannot already do. A page that needs to query across objects, run complex business logic, call external services, or render a UI that does not map cleanly to a single record needs a Custom Controller. Sample use cases: a search page that queries Knowledge articles plus Cases plus Contacts in one query, a wizard that walks through multi-step form input, a dashboard page that aggregates records across the org.
How Custom Controllers work in Visualforce
Defining a Custom Controller
A Custom Controller is a public Apex class with public getter methods, public setter methods, and public action methods (typically returning a PageReference). The class is declared on the Visualforce page through the controller attribute. The page can then reference any property on the class through the merge syntax and call any action method through commandButton actions.
Getters, setters, and the page-load lifecycle
When the Visualforce page renders, the framework calls getter methods on the controller to get the data needed for the page. Setters are called when form input is submitted. Action methods are called when the user clicks a commandButton or commandLink. The lifecycle is request-response: the controller is instantiated per request, properties are populated, getters fire, the page renders, and the controller is destroyed.
Action methods and PageReference returns
Action methods are public methods on the controller that handle user actions. They return a PageReference, which is either a redirect (returning new PageReference pointing to a new path) or null (re-render the current page). Returning null is the most common pattern; it lets the framework re-render with updated state.
Custom Controller vs Standard Controller vs Extension
Standard Controller is object-bound and provides default CRUD operations. Custom Controller is from-scratch with no defaults. Extension wraps a Standard Controller (or another Custom Controller) with additional methods. Pick Standard for simple record-edit pages, Custom for cross-object or non-CRUD logic, Extension for adding a small amount of custom logic to an otherwise standard page.
Governor limits and Custom Controllers
Custom Controllers run in Apex and are bound by all standard Apex governor limits: 100 SOQL queries per transaction, 150 DML statements, 6 MB heap. The biggest gotcha is the view state: every public property on the Custom Controller is serialized into the page view state, which is sent to the browser on each render. Large objects in view state quickly exhaust the 170 KB view state limit and cause page errors.
Modern alternatives: LWC and Aura
For new development, do not write a Custom Controller. Use Lightning Web Components with Apex controllers (called from AuraEnabled methods). LWC has no view state limit, runs in the modern Lightning runtime, and supports the modern Salesforce data layer (Lightning Data Service, wire adapters). Custom Controllers are for maintaining existing Visualforce pages, not greenfield development.
Testing Custom Controllers
Custom Controllers require Apex tests like any other Apex class. The test pattern is to instantiate the controller, set its properties to simulate page input, call action methods, and assert the resulting state. PageReference returns and view state changes can be verified through ApexPages.currentPage and the controller properties.
How to build and maintain a Custom Controller
Writing a Custom Controller is standard Apex development with Visualforce-specific patterns for getters, setters, and action methods. The work is mostly about understanding the page lifecycle.
- Define the Apex class
From Setup or Developer Console, create a new Apex class. Make it public. Add public properties for data the page needs, getter methods for computed values, and action methods for button handlers.
- Reference the controller from the Visualforce page
Set the apex:page controller attribute to the class name. Reference properties through the merge syntax and action methods through commandButton actions.
- Handle form input
Add public setter properties for each form field. Salesforce auto-populates them on form submit. Validate values inside the action method, not the setter, to avoid surprise side effects.
- Manage view state
Mark large properties as transient to keep them out of view state. Query results that are needed on the current request but not on the next can stay transient.
- Write Apex tests
Build a test class that instantiates the controller, sets input properties, calls action methods, and asserts state transitions and PageReference returns. Aim for 75 percent code coverage minimum.
- Migrate to LWC when feasible
For pages that get heavy use or face performance issues, rebuild as LWC with an Apex controller called through AuraEnabled. The modern stack is faster and more maintainable.
- View state is serialized on every page render. Large collections in public properties exhaust the 170 KB view state limit and cause runtime errors.
- Action methods that perform DML must respect Apex governor limits. The 150 DML statements per transaction limit can be reached fast on bulk operations.
- Setters fire on form submit in arbitrary order. Do not rely on order-of-setter execution for business logic.
- Custom Controllers do not work in Lightning Experience the same way as in Classic. Test in both contexts; some behaviors render differently.
- Custom Controllers cannot be deleted if they are referenced by a Visualforce page. Delete the page references first.
Trust & references
Cross-checked against the following references.
- Custom Controllers in VisualforceSalesforce Developers
- Apex Developer GuideSalesforce Developers
Straight from the source - Salesforce's reference material on Custom Controller.
- Visualforce Developer GuideSalesforce Developers
Hands-on resources to go deeper on Custom Controller.
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 a Custom Controller?
Q2. When is a Custom Controller the right choice?
Q3. Where is the Custom Controller specified on a Visualforce page?
Discussion
Loading discussion…