Skip to main content
New tool CRON Expression Builder — preview next run times before you schedule Apex. Open the builder →
Interview prep

Visualforce interview questions and answers

View state, controllers, and where it still beats LWC.

8 questions · 2 of them scenarios

Junior round

Junior Visualforce questions

Visualforce junior

Standard controller, custom controller, or an extension?

Testing What you say about security. The three options differ there and the answer usually skips it.

junior

A standard controller when the page works with one record and I want the built-in behaviour — save, edit, delete, cancel all come free, and it enforces the user's access to the record. A custom controller when the page is not tied to one record and I am writing the logic myself. An extension when I want the standard controller's behaviour plus a few methods of my own.

mid

The functional split is straightforward and the security difference is the one worth stating. A standard controller respects the running user's sharing and field access, because the platform is doing the record access. A custom controller runs in system mode unless I declare with sharing, so a page built on one will happily show a record the user has no right to see — that is not a bug in the page, it is the default, and it is why an extension on a standard controller is often the safer shape for a record page. The other practical reason to prefer the standard controller where I can is that it manages the record's state for me, so there is less in the view state and fewer ways to get the save semantics wrong.

Deep dive on this
Visualforce junior

Why does anyone still write Visualforce?

Testing Whether you know the specific jobs it still owns, or treat it as legacy in general.

junior

Because a few things have no Lightning equivalent. Rendering a PDF is the main one — a page with renderAs="pdf" produces a document, and there is no component that does that. Visualforce email templates are another, and so is returning a file directly with a contentType on the page. Beyond those, new work goes to Lightning web components and Visualforce is what I maintain rather than what I choose.

mid

It owns a short list of jobs and I would rather know that list than argue about the platform. PDF generation with renderAs="pdf", Visualforce email templates, and returning a raw file by setting contentType on the page — those three come up regularly and none of them have a component-based replacement. There is also a large volume of it in older orgs, and a page that works and is not being changed is not technical debt worth a project. Where I do intervene is when somebody is about to extend a Visualforce page substantially, because at that point the choice is between growing something that has no future and putting the new part in a component and embedding it.

Mid-level round

Mid-level Visualforce questions

Visualforce mid

How would you get a Lightning web component onto a Visualforce page?

Testing Which constraints you name. It works, and it is not a drop-in.

mid

Lightning Out. The page includes apex:includeLightning, creates an app reference, and calls $Lightning.createComponent to mount the component into a div. The component needs to be exposed for that target in its metadata, and I need a Lightning app as the dependency container. It is the normal route for modernising a page I cannot replace outright — the old page stays, the new part is a component I can reuse elsewhere.

senior

The mechanism is stable and the friction is in the context rather than the code. The component runs inside a page that has its own styling, so Lightning Design System classes may not resolve the way they do in a Lightning page, and I plan for the page to look slightly wrong before it looks right. Communication is the part worth designing rather than improvising: events from the component do not reach the Visualforce controller, so anything the page has to know about goes through a callback handed to $Lightning.createComponent at creation, or through Lightning Message Service, which does cross that boundary. And I would be deliberate about not straddling the two — a component that renders inside the page but saves through the page's controller has two owners for the same record and gets confusing quickly. The cleaner shape is the component owning its own data through Lightning Data Service and the page being a host.

Deep dive on this
Visualforce mid

What is view state, and how do you keep it under control?

Testing How concrete you can be about what goes into it. Vague answers here mean the page has not been debugged yet.

mid

View state is the serialised state of the page's controller, sent to the browser and back on every postback, and it has a hard ceiling of 170 KB. Everything reachable from a non-static controller member goes into it — a List<Account> of 5,000 records included — so the usual cause of a view state error is a collection somebody put in an instance variable. The lever is the transient keyword, which excludes a member from serialisation, so anything I can recompute per request should be transient.

senior

The mental model that helps is that view state is the price of stateful postbacks, so the fix is usually to be less stateful rather than to compress what you are keeping. Concretely: mark anything recomputable as transient, hold Ids rather than records where the page only needs a handful of fields, and page the data instead of loading a whole list into a member. The one that catches people is that view state includes objects reachable from your members, so a wrapper class holding an sObject holds all its fields — including any large text area — and one blob field on 200 rows is the whole budget. Where I would go further is questioning the postback model itself: JavaScript remoting through @RemoteAction carries no view state at all, so a page whose interactive parts move to remoting stops having this class of problem rather than managing it. The view state inspector in the developer console is what settles arguments here, since it shows the actual bytes per member instead of a guess.

Visualforce mid scenario

A Visualforce page throws a view state error for some users and not others. How do you narrow it down?

Testing That "some users" is a clue about data volume rather than about permissions.

What they tell you

A page listing a customer's orders throws Maximum view state size limit (170KB) exceeded for a handful of users. The same page works for everyone else. The controller holds the order list in an instance variable.

mid

Some users and not others, on a page whose size depends on a list, points at data volume rather than anything about the users themselves — the affected people are almost certainly the ones with the biggest customers. The list is in an instance variable, so all of it is serialised into the view state on every postback, and one big account takes it past 170 KB. The fix is to stop keeping it: mark it transient and requery per request, or hold only the Ids and the few fields the page shows.

senior

I would confirm the correlation before fixing anything, because if it is not volume then the diagnosis is wrong — a query joining the affected users to their record counts takes a minute and makes the rest of the work justified. Assuming it is, the view state inspector tells me exactly which member is spending the budget, and I would rather read that than infer it, since the answer is sometimes not the obvious list but a wrapper holding whole sObjects with a long text field on each. The fix has two levels. Immediately, transient on the list and a requery, or a projection into a small wrapper carrying only the columns displayed — either brings it well under the ceiling. Structurally, a page whose state grows with a customer's data will hit this again at the next threshold, so if this page is going to live for years I would move the interactive part to @RemoteAction, which carries no view state at all. And whichever route, the test needs to run against the largest real account rather than a sandbox record with three orders, because that omission is why this reached production.

Ask before you answer
  • Do the affected users work with the largest customers, in terms of order count?
  • Is the order list an instance variable, and does it hold whole sObjects or a wrapper?
Do not say this

Add pagination to the page so fewer rows are displayed at a time.

Displaying fewer rows does not shrink the view state if the controller still loads the whole list into a member — the state is what the controller holds, not what the page renders. The page will get slightly faster and fail for the same users.

Senior round

Senior Visualforce questions

Visualforce senior

You have 60 Visualforce pages and a mandate to modernise. How do you plan it?

Testing Whether you would migrate all 60. The right answer involves migrating far fewer than that.

mid

I would sort them before planning anything. A large share of 60 pages will be unused — old buttons, pages behind features nobody runs — and those get deleted rather than migrated. Of what remains, some cannot move at all: anything rendering a PDF, any Visualforce email template. What is left is the real list, and I would prioritise by how often users touch it, taking the busiest pages first so the benefit arrives early.

senior

The plan starts by shrinking the problem, because migrating 60 pages is a project nobody funds and migrating eight is a quarter's work. Three buckets. Delete: pages with no traffic, which the login and page-view data will identify, and there are always more than anyone expects. Cannot migrate: renderAs="pdf" and email templates have no component equivalent, so those stay and should be documented as deliberate rather than left looking unfinished. Migrate: what is left, ordered by usage rather than by how unpleasant the code is. For those, Lightning Out is a useful middle step — the new functionality goes in a component embedded in the existing page, so each release is small and reversible, and the page is retired once nothing but the shell remains. What I would resist is a rewrite of a page that works, has no traffic problem and nobody is asking to change, because the only thing that buys is consistency, and consistency is not worth a regression on a page that handles orders. The honest version of the mandate is usually "stop building new things in Visualforce", and agreeing that explicitly is worth more than a migration schedule that slips.

Visualforce senior scenario

A PDF invoice page works in testing and fails for the largest customers. How do you fix it?

Testing The difference between making one document render and making the design hold at the top of the range.

What they tell you

A Visualforce page with renderAs="pdf" builds an invoice from order lines. It works for typical orders. For the ten largest customers it either times out or throws a heap size error. Those are the invoices the finance team cares most about.

mid

A page that works small and fails large is running out of one of two things: the 6 MB heap available to a synchronous request, which surfaces as System.LimitException: Apex heap size too large, or the time a request is allowed. So the first thing I would do is find out how many lines the biggest invoice has, and whether the controller is holding all of them plus a wrapper per line. Reducing what is in memory — querying only the fields the template prints, avoiding a wrapper per row — often gets it under. Beyond that the honest answer is that a document that large should not be generated in a page request at all.

senior

I would separate the immediate and the structural, because finance needs invoices this month either way. Immediately: measure the largest one, then cut what the request holds. Querying only the printed fields, dropping per-row wrapper objects, and stripping heavy images or embedded fonts routinely halves the footprint, and that may be enough to clear the 6 MB heap for the current top ten. What I would not do is treat that as the fix, because those customers are growing and the ceiling is not moving. Structurally, generating a large document synchronously in a page request is the wrong shape: the version that holds is asynchronous — a Queueable that renders and attaches the file, and a UI that tells the user it is coming. That gets the larger heap available to async and removes the request timeout from the picture entirely. The other option worth putting on the table is an external rendering service, which is more work and more control, and it becomes the right answer as soon as somebody asks for a layout Visualforce cannot express. Whichever route, the test data needs to include the biggest real customer, because testing on a typical order is exactly how this reached the finance team.

Ask before you answer
  • How many order lines does the largest invoice have, and how does that compare to the ones that work?
  • Is the controller building the whole document in memory, and does the page include images or a web font?
Do not say this

Raise the page's timeout and split the biggest invoices by hand each month.

There is no timeout to raise on a synchronous page request, and manual handling of the ten most important invoices puts the finance team's month end on a person's memory. It also leaves the failure exactly where it will grow, since those customers are the ones getting bigger.

Visualforce senior

@RemoteAction or apex:actionFunction — when does the difference matter?

Testing Where you have felt the difference. On a small page there is none; on a busy one there is a lot.

mid

apex:actionFunction does a postback: the whole view state goes to the server and comes back, the controller's state is available, and the page re-renders whatever I told it to. @RemoteAction is JavaScript remoting — a static method, no view state at all, JSON in and out, and I update the DOM myself. So remoting is much lighter and gives me nothing for free, and a postback is heavier and keeps the page's state coherent.

senior

The difference is which model the page is really using. A postback treats the page as server-rendered with state living in the controller, which is coherent and costs the full view state round trip on every interaction — fine for a form, painful for anything that fires on typing or scrolling. Remoting treats the page as a client with an API behind it, so it is fast and stateless, and the cost lands on me: the method has to be static, so it cannot see the controller's members, and everything the call needs has to be passed in explicitly. That constraint is usually a good thing, because it produces a method that is testable on its own. Two things I would watch. A @RemoteAction is a callable entry point like any @AuraEnabled method, so it needs its own access checks — being on a page the user can reach is not authorisation. And mixing the two on one page means some interactions refresh the controller's state and others do not, which produces the class of bug where the screen disagrees with itself depending on what you clicked last.

Deep dive on this