Skip to main content

Store Settings Getters

Store-wide values a merchant can change from the admin panel — currency, units, address, rounding, catalog behaviour — live in the setting table, not in config/. These getters read them.

Every getter follows the same three-step resolution: admin setting → config fallback → hard default. That is why an upgraded store behaves exactly as it did before the merchant ever opens the settings page.

The sync / async split

This is the distinction that matters most on this page.

Synchronous gettersAsynchronous getters
ReadsAn in-memory cache only. Never touches the database.The same cache — but populates it from the database on the first call.
Cold cacheReturns the config fallback / hard default.SELECT * FROM setting, then answers.
Safe inHot and genuinely synchronous paths — the pricing formatter, cart build, Handlebars email helpers, AJV schema builders, the SSR context builder, pagination filters.Everything else. Prefer these when you can await.

The cache is warmed at boot by modules/setting/bootstrap.ts (in every process that loads module bootstraps — HTTP, cron, subscriber) and refreshed whenever a setting is saved. A warm-up failure is non-fatal: on a brand-new database the setting table does not exist yet, and the async path lazy-loads later.

A synchronous getter on a cold cache returns the fallback, not the stored value

getSettingSync has no way to wait. Before boot warm-up completes — in a unit test with no database, for instance — it returns defaultValue. That is the deliberate trade that makes it safe inside toPrice. If you need the stored value guaranteed, use the async getter.

Values coming back from the setting table are TEXT ("true", "20", "ceil"), while a config fallback is already a real boolean or number. The typed getters below coerce both shapes, so you never have to compare against a stray string. Raw getSetting / getSettingSync do not coerce — they only JSON.parse rows stored as JSON.


Core setting functions

import {
getSetting,
getSettingSync,
refreshSetting
} from '@evershop/evershop/setting/services';

getSetting

getSetting<T>(name: string, defaultValue: T): Promise<T>

Read one setting by name. Loads the whole setting table into the cache on the first call, then serves from memory. Rows persisted as JSON (objects and arrays, such as storeLanguages) are parsed back; malformed JSON falls back to defaultValue.

getSettingSync

getSettingSync<T>(name: string, defaultValue: T): T

The synchronous companion. Reads the already-loaded cache and never touches the database. Returns defaultValue when the cache is cold or the row is absent.

refreshSetting

refreshSetting(): Promise<void>

Reload the cache from the database. Call it after writing settings outside the admin save path.

import { getSetting, getSettingSync, refreshSetting } from '@evershop/evershop/setting/services';

const banner = await getSetting<string | null>('promoBanner', null);

// Inside a synchronous formatter:
const currencySymbolStyle = getSettingSync<string>('currencyDisplay', 'symbol');

await refreshSetting();

Store identity and address

import {
getStoreName,
getStoreDescription,
getStoreEmail,
getStorePhoneNumber,
getStoreCountry,
getStoreProvince,
getStoreCity,
getStoreAddress,
getStorePostalCode
} from '@evershop/evershop/setting/services';

All asynchronous.

FunctionReturnsSetting nameDefault
getStoreName(defaultValue?)Promise<string>storeName'Evershop', overridable via the argument
getStoreDescription()Promise<string | null>storeDescriptionnull
getStoreEmail()Promise<string | null>storeEmailnull
getStorePhoneNumber()Promise<string | null>storePhoneNumbernull
getStoreCountry()Promise<string | null>storeCountrynull
getStoreProvince()Promise<string | null>storeProvincenull
getStoreCity()Promise<string | null>storeCitynull
getStoreAddress()Promise<string | null>storeAddressnull
getStorePostalCode()Promise<string | null>storePostalCodenull

These five address getters are exactly what getOriginAddress() composes into the shipping origin.


Currency, units and timezone

import {
getStoreCurrency,
getStoreTimezone,
getWeightUnit,
getDimensionUnit
} from '@evershop/evershop/setting/services';

All synchronous and cache-only, because they are read inside the pricing formatter, cart build and email helpers.

FunctionReturnsSetting → config fallback → default
getStoreCurrency()stringstoreCurrencyshop.currency'USD'
getStoreTimezone()stringstoreTimeZoneshop.timezone'UTC'
getWeightUnit()stringweightUnitshop.weightUnit'kg'
getDimensionUnit()stringdimensionUnitshop.dimensionUnit'cm'
shop.currency, shop.weightUnit and shop.dimensionUnit are gone from getConfig

They were removed from the typed configuration surface — they are admin settings now. The getters above still read them untyped as a backward-compatible fallback, but getConfig('shop.currency') no longer typechecks.

Two further notes:

  • getStoreTimezone() is the display timezone (it drives the DateTime GraphQL type). It is not the database session timezone, which stays on shop.timezone in config and is applied by the pool at connection time.
  • Changing a weight or dimension unit relabels stored values; it does not convert them. Product and package measurements are unit-less numbers.

Languages

import {
getStoreLanguage,
getEnabledLanguages,
getAdditionalLanguages,
getAdminLanguage
} from '@evershop/evershop/setting/services';

All asynchronous.

FunctionReturnsDescription
getStoreLanguage()Promise<string>The default storefront locale. storeLanguage (normalised) → config shop.language'en'.
getEnabledLanguages()Promise<string[]>The deduped union of the default and the configured storeLanguages list, default first. The default is always enabled; a default that also appears in the additional list is simply deduped.
getAdditionalLanguages()Promise<string[]>The enabled set minus the default — what the admin form shows under "Additional languages". Strips the default even when a legacy storeLanguages value still contains it.
getAdminLanguage()Promise<string>The admin panel locale, independent of the storefront. adminLanguage (normalised) → 'en'.
const [defaultLocale, enabled] = await Promise.all([
getStoreLanguage(),
getEnabledLanguages()
]);
// defaultLocale: 'en'
// enabled: ['en', 'fr', 'de']

Checkout and pricing settings

import {
getAllowGuestCheckout,
getPricePrecision,
getPriceRounding
} from '@evershop/evershop/checkout/services';

All three are synchronous — they are read inside toPrice, the promotion calculators, the order validator and request handlers.

FunctionReturnsSetting → config fallback → default
getAllowGuestCheckout()booleanallowGuestCheckoutcheckout.allowGuestCheckouttrue
getPricePrecision()numberpricingPrecisionpricing.precision2
getPriceRounding()RoundTypepricingRoundingpricing.rounding'round'

getPriceRounding() returns one of 'round' | 'ceil' | 'floor' | 'up' | 'down'. round, ceil and floor are the admin values; up and down are accepted legacy aliases so a pre-existing config value still flows through unchanged. An unrecognised value falls back to 'round'.


Catalog behaviour settings

import {
getShowOutOfStockProducts,
getCollectionPageSize,
getProductImageDimensions
} from '@evershop/evershop/catalog/services';

All synchronous — they run in the pagination filter and the SSR context builder.

FunctionReturnsSetting → config fallback → default
getShowOutOfStockProducts()booleancatalogShowOutOfStockProductcatalog.showOutOfStockProductfalse
getCollectionPageSize()numbercatalogCollectionPageSizecatalog.collectionPageSize20. Clamped to a minimum of 1.
getProductImageDimensions(){ width: number; height: number }catalogProductImageWidth / catalogProductImageHeightcatalog.product.image.width / .height1200 each
import { getCollectionPageSize } from '@evershop/evershop/catalog/services';

const limit = getCollectionPageSize(); // 20

See Also