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, and 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 and multi-currency orgs
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 and 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