Skip to content
Salesforce Dictionary - Free Salesforce GlossarySalesforce Dictionary
Full Custom Controller entry
How-to guide

How to build a custom controller

You build a custom controller by writing an Apex class and pointing a Visualforce page at it. Here is the minimal path from empty class to a working page, with the choices that matter at each step.

By Dipojjal Chakrabarti · Founder & Editor, Salesforce DictionaryLast updated Jun 16, 2026

You build a custom controller by writing an Apex class and pointing a Visualforce page at it. Here is the minimal path from empty class to a working page, with the choices that matter at each step.

  1. Create the Apex class

    In Setup, go to Apex Classes and click New, or create the class in your IDE. Declare it public, add the with sharing keyword unless you have a documented reason not to, and give it a no-argument constructor. Run any initial queries in that constructor and store results in member variables.

  2. Expose data with properties

    Add public properties using get; set; for anything the page reads or writes. A property named searchTerm becomes {!searchTerm} on the page. Keep getters cheap; do not run SOQL inside a getter that the page calls during rendering.

  3. Write action methods

    Add public methods that return PageReference for each button or link. Return null to re-render in place, or a new PageReference to redirect. Run all DML inside these action methods, never inside getters.

  4. Bind the page to the class

    Create the Visualforce page and set controller="YourClassName" on the apex:page tag. Reference your properties with merge expressions and wire buttons with action="{!yourMethod}". Wrap inputs in apex:form so postbacks work.

  5. Write the test class

    Create an Apex test that instantiates the controller, sets properties, sets any URL parameters with ApexPages.currentPage().getParameters().put, calls the action methods, and asserts on the returned PageReference and the controller state.

Class access modifierrequired

The class must be public (or global). The controller attribute cannot bind to a private class.

No-argument constructorrequired

The framework instantiates a custom controller with a parameterless constructor, so one must exist (the implicit default counts if you write no constructor at all).

controller attributerequired

The apex:page tag must set controller="ClassName" to link the page to the custom controller. This is what makes every expression resolve against your class.

Public properties and methodsrequired

Anything the page references, getters, setters, and action methods, must be public. Private members are invisible to the page and the expression will fail to resolve.

Gotchas
  • Without with sharing, the controller runs in system mode and can surface records the user is not allowed to see.
  • A getter that runs SOQL is called multiple times per render and will burn query limits fast; query once and cache in a variable.
  • Large non-transient member variables inflate view state toward the 170 KB cap; mark anything not needed next request as transient.
  • DML in a getter throws an error because rendering is read-only; move all inserts, updates, and deletes into action methods.

See the full Custom Controller entry

Custom Controller includes the definition, worked example, deep dive, related terms, and a quiz.