Skip to main content

SF-0311 · Concept · Medium

What are annotations in apex? Or what are the annotations supported by apex?

✓ Verified by Vikas Singhal · Last reviewed 5/17/2026 · Updated for Spring '26

Annotations in Apex are markers that begin with @ and attach to a class, method, or field. They tell the compiler or runtime to treat that element specially — run it as a test, expose it to a Lightning component, defer it asynchronously, override default visibility for tests, and so on. Most are platform-specific behaviours you cannot get any other way.

The annotations you’ll use most

AnnotationApplies toWhat it does
@isTestClass or methodMarks code as a test; doesn’t count against the org’s code size limit
@TestSetupMethod in a @isTest classRuns once before each test method to seed shared data
@TestVisibleField or methodMakes a private/protected member accessible only from test classes
@futureStatic methodRuns asynchronously in a separate transaction
@AuraEnabledMethod or fieldExposes to Lightning Web Components and Aura; cacheable=true enables client caching
@InvocableMethodStatic methodMakes the method callable from Flow
@InvocableVariableFieldExposes the field as a Flow input/output parameter
@RestResourceClassMaps the class to a REST endpoint URL
@HttpGet, @HttpPost, @HttpPut, @HttpDelete, @HttpPatchStatic method in @RestResource classMaps the method to an HTTP verb
@ReadOnlyMethodRaises the query row limit to 1 million (no DML allowed in scope)
@RemoteActionStatic methodExposes to JavaScript Remoting in Visualforce
@DeprecatedClass or methodMarks managed-package member as deprecated for subscribers
@SuppressWarningsClass or methodSuppresses specific PMD warnings (often used with 'PMD.ApexDoc')
@NamespaceAccessibleMember in a managed packageExposes to other classes in the same namespace
@JsonAccessClassRestricts JSON.deserialize from creating instances
@RestResource, @SchedulableContext, @QueueableContextVariousPlatform-specific contracts

@isTest and @TestSetup

@isTest
public class AccountServiceTest {

    @TestSetup
    static void seedData() {
        insert new List<Account>{
            new Account(Name = 'Test 1', Industry = 'Technology'),
            new Account(Name = 'Test 2', Industry = 'Finance')
        };
    }

    @isTest
    static void getActive_returnsRecords() {
        Test.startTest();
        List<Account> result = AccountService.getActive(10);
        Test.stopTest();
        System.assert(!result.isEmpty(), 'Expected non-empty result');
    }
}

@isTest classes are not counted against the 6 MB Apex code size limit per org — that’s why test code is segregated, and why production deploys require 75% coverage from these @isTest classes specifically.

@TestVisible

You want methods and fields to be private for normal callers but reachable from tests. @TestVisible makes that possible without weakening production encapsulation.

public class OrderProcessor {
    @TestVisible private Boolean dryRun = false;
    @TestVisible private void rollback() { /* ... */ }
}

@isTest
static void testRollback() {
    OrderProcessor p = new OrderProcessor();
    p.dryRun = true;          // OK only because of @TestVisible
    p.rollback();
}

@future

The original async-Apex annotation. The method runs in a separate transaction, after the current one commits.

public class IntegrationCallouts {
    @future(callout=true)
    public static void notifyExternalSystem(Set<Id> accountIds) {
        // Runs async, with HTTP callout permission, in its own governor limit budget
    }
}

Limitations: parameters must be primitives or collections of primitives (no sObjects), cannot be called from another @future, no return value. Modern code mostly prefers Queueable for the same reasons plus richer parameter types.

@AuraEnabled

The bridge between Apex and Lightning. Methods marked @AuraEnabled are callable from @wire and imperative-apex in LWC. Fields marked @AuraEnabled are serialized to JSON when the runtime sends data to the client.

public with sharing class AccountController {
    @AuraEnabled(cacheable=true)
    public static List<Account> getRecentAccounts() {
        return [SELECT Id, Name FROM Account ORDER BY CreatedDate DESC LIMIT 10];
    }
}

cacheable=true opts the result into the Lightning client cache — required for @wire. Methods that perform DML cannot be cacheable.

@InvocableMethod

The Flow integration point. Annotate a method as @InvocableMethod and it appears as an Apex Action in Flow Builder.

public class FlowActions {
    @InvocableMethod(label='Recompute Total' description='Recomputes order total')
    public static List<Decimal> recompute(List<Id> orderIds) {
        List<Decimal> totals = new List<Decimal>();
        // ... compute ...
        return totals;
    }
}

Inputs and outputs must be lists (Flow calls in bulk). Each input is a list, each output is a list — Flow correlates by position.

@RestResource

Custom REST endpoints. The annotation maps the class to a URL pattern; method annotations map HTTP verbs.

@RestResource(urlMapping='/orders/*')
global with sharing class OrderResource {
    @HttpGet
    global static Order__c get() {
        String id = RestContext.request.requestURI.substringAfterLast('/');
        return [SELECT Id, Name FROM Order__c WHERE Id = :id LIMIT 1];
    }
    @HttpPost
    global static Id create(String name) {
        Order__c o = new Order__c(Name = name);
        insert o;
        return o.Id;
    }
}

Class and methods must be global. The URL is /services/apexrest/orders/<id>.

@ReadOnly

Raises the synchronous query row limit from 50,000 to 1,000,000. Use for very large read-only operations, like generating a one-time report. The trade-off: no DML inside the annotated method’s call stack.

What interviewers are really looking for

Naming a handful of annotations covers the basic answer. The interview-worthy answer groups them by purpose: testing (@isTest, @TestSetup, @TestVisible), async (@future), UI integration (@AuraEnabled), Flow (@InvocableMethod), API (@RestResource + HTTP verbs), and packaging (@Deprecated, @NamespaceAccessible). If you can also name the constraints — @future parameter limits, @AuraEnabled(cacheable=true) no-DML rule, @RestResource global requirement — you’ve shown the depth that comes from shipping production code.

Verified against: Apex Developer Guide — Annotations. Last reviewed 2026-05-17 for Spring ‘26 release.