UserInfo.getDefaultCurrency() returns the current user's personal default currency as an ISO 4217 code (e.g. "USD"). In a single-currency org every user shares the same value, so it's effectively the org's currency. In a multi-currency org each user has their own personal default — which is rarely what you want for record-level logic. Read CurrencyIsoCode off the record instead.
The method returns a String — never null in a properly licensed org
UserInfo.getDefaultCurrency() returns a non-null ISO 4217 code for any running user in an org with currencies enabled. If you're seeing null, the most common reasons are:
- The org has multi-currency disabled. In that case the method still returns the org's single currency — null indicates something else is wrong.
- You're running in a context where
UserInfoisn't fully populated — anonymous Apex in a fresh session, certain batch contexts, or test execution withSeeAllData=falseand no test user setup. - The org has currencies disabled at the platform level — extremely rare, but possible in trial/demo orgs.
Single-currency vs multi-currency — the behaviour you actually need to know
Single-currency org
One currency, set at org creation. Every user's default currency equals the org's currency. UserInfo.getDefaultCurrency() returns that single code:
String c = UserInfo.getDefaultCurrency();
// c == 'USD' (or 'EUR', 'GBP', etc — whatever the org was created with)
// Same value for every user in the org.Multi-currency org
Multiple currencies enabled. Each user has a personal default currency (configurable on their User record). Records have their own CurrencyIsoCode field. UserInfo.getDefaultCurrency() returns the running user's personal default — not the org's corporate currency, not the record's currency:
// In a multi-currency org:
String userDefault = UserInfo.getDefaultCurrency();
// userDefault == the running user's personal default (e.g. 'EUR' for a European sales rep)
// If you need the record's currency, read it off the record:
Account a = [SELECT Id, CurrencyIsoCode FROM Account WHERE Id = :acctId];
String recordCurrency = a.CurrencyIsoCode;How to get the org's corporate currency safely
In a single-currency org there is only one currency, so any approach works. In a multi-currency org you usually want the corporate currency — the one with IsCorporate = true on the CurrencyType object:
String corporateCurrency;
if (UserInfo.isMultiCurrencyOrganization()) {
CurrencyType corp = [
SELECT IsoCode FROM CurrencyType WHERE IsCorporate = true LIMIT 1
];
corporateCurrency = corp.IsoCode;
} else {
// Single-currency org — UserInfo is authoritative
corporateCurrency = UserInfo.getDefaultCurrency();
}UserInfo.isMultiCurrencyOrganization() is the canonical gate. It also lets your code compile cleanly in both org types — selecting from CurrencyTypein a single-currency org throws a compile error, so the conditional matters.
What to use when
- Reporting a value in the running user's preferred unit:
UserInfo.getDefaultCurrency()is correct. - Persisting a value on a record: use the record's
CurrencyIsoCodefield. Don't rely on the user's default — the user changes, the record's currency shouldn't. - Reporting at the org level: read the
IsCorporateentry onCurrencyType. - Cross-org / managed package code: always gate on
UserInfo.isMultiCurrencyOrganization()first.
Test both org modes locally — without provisioning two scratch orgs
The annoying part of currency code is that bugs only surface in one of the two org types. Nimbus lets you switch between single-currency and multi-currency modes in nimbus.properties and re-run your tests in milliseconds:
# Single-currency mode (default)
nimbus.org.currency=USD
# Multi-currency mode — sets the corporate currency and enables CurrencyType
nimbus.org.multi-currency=true
nimbus.org.currency=USD
nimbus.org.currencies=USD,EUR,GBP,JPY