Documentation Index Fetch the complete documentation index at: https://docs.grainql.com/llms.txt
Use this file to discover all available pages before exploring further.
What is Remote Configuration?
Remote configuration lets you change how your app behaves without shipping new code. Update text, toggle features, or change colors - all from the Grain dashboard.
Traditional way :
const heroText = "Welcome!" ; // Hardcoded - requires deploy to change
With remote config :
const heroText = grain . getConfig ( 'hero_text' ); // Dynamic - change anytime
Now you can update that text from the dashboard and all users see the new version instantly.
Why Use Remote Config?
A/B Testing : Show variant A to some users, variant B to others:
const variant = grain . getConfig ( 'hero_variant' ); // 'A' or 'B'
Feature Flags : Enable/disable features without code:
if ( grain . getConfig ( 'new_ui_enabled' ) === 'true' ) {
// Show new UI
}
Personalization : Different content for different users:
// Premium users see different text
const message = grain . getConfig ( 'welcome_message' );
Emergency Off Switch : Disable broken features instantly:
if ( grain . getConfig ( 'chat_enabled' ) !== 'false' ) {
// Show chat widget
}
Cache-First Strategy
This is the key to making remote config fast. Grain uses a cache-first approach:
First access : Return default or cached value (instant)
Background fetch : Load fresh values from API
Update : When new values arrive, update cache and notify listeners
Your app never waits for the network. It shows content immediately with cached or default values.
// Returns instantly from cache or defaults
const heroText = grain . getConfig ( 'hero_text' );
// Meanwhile, fresh values load in the background
// When they arrive, listeners are notified
Setting Defaults
Always provide default values for immediate access:
Using the Grain Tag:
< script src = "https://tag.grainql.com/v4/your-tenant-id.js" ></ script >
< script >
const grain = GrainTag . getInstance ();
// Works immediately, even offline
const heroText = grain . getConfig ( 'hero_text' ); // "Welcome!"
</ script >
Or with the npm package:
import { GrainTag } from '@grainql/tag' ;
const grain = GrainTag . init ({
tenantId: 'your-tenant-id' ,
defaultConfigurations: {
hero_text: 'Welcome!' ,
button_color: 'blue' ,
feature_enabled: 'false'
}
});
// Works immediately, even offline
const heroText = grain . getConfig ( 'hero_text' ); // "Welcome!"
Without defaults, getConfig() returns undefined until values load from the API.
Getting Configuration Values
Synchronous Access
Get values instantly from cache or defaults:
// Returns immediately
const heroText = grain . getConfig ( 'hero_text' );
const buttonColor = grain . getConfig ( 'button_color' );
Use this in render functions, event handlers, or anywhere you need instant access.
Asynchronous Access
Fetch fresh values from the API:
// Fetches from API (cache-first)
const heroText = await grain . getConfigAsync ( 'hero_text' );
This still uses cache-first: returns cached value immediately, then fetches fresh value in background.
Force refresh :
// Skip cache, fetch directly from API
const heroText = await grain . getConfigAsync ( 'hero_text' , {
forceRefresh: true
});
Get All Configurations
// Synchronous: from cache/defaults
const configs = grain . getAllConfigs ();
console . log ( configs ); // { hero_text: "Welcome!", button_color: "blue", ... }
// Asynchronous: fetch from API
const configs = await grain . getAllConfigsAsync ();
Preloading Configurations
Preload configs at app startup for instant access:
// On app load
grain . setUserId ( 'user_123' );
await grain . preloadConfig ([ 'hero_text' , 'button_color' , 'feature_enabled' ]);
// Now these are available synchronously
const heroText = grain . getConfig ( 'hero_text' );
This is perfect for loading critical configs before rendering your UI.
Configuration Change Listeners
React to configuration changes in real-time:
// Listen for updates
grain . addConfigChangeListener (( configs ) => {
console . log ( 'Configs updated:' , configs );
// Update your UI
document . getElementById ( 'hero' ). textContent = configs . hero_text ;
});
When listeners fire :
After background fetch completes
When manual refresh happens
When cache updates
Remove listeners when no longer needed:
const listener = ( configs ) => { /* ... */ };
grain . addConfigChangeListener ( listener );
// Later...
grain . removeConfigChangeListener ( listener );
Personalized Configurations
Pass user properties to get personalized values:
const heroText = await grain . getConfigAsync ( 'hero_text' , {
properties: {
plan: 'premium' ,
location: 'US'
}
});
How it works : Grain evaluates rules based on these properties and returns values matched to the user. Premium users might see different text than free users.
Set up rules in the Grain dashboard to define which users see which values.
Practical Examples
Feature Flag
// Simple feature flag
const newUIEnabled = grain . getConfig ( 'new_ui_enabled' );
function App () {
return newUIEnabled === 'true' ? < NewUI /> : < LegacyUI />;
}
A/B Test
// A/B test with variants
const heroVariant = grain . getConfig ( 'hero_variant' ); // 'A' or 'B'
const variants = {
A: { title: 'Welcome!' , color: 'blue' },
B: { title: 'Hello there!' , color: 'green' }
};
const content = variants [ heroVariant || 'A' ];
Dynamic Styling
// Remote controlled theme
const primaryColor = grain . getConfig ( 'primary_color' );
const borderRadius = grain . getConfig ( 'border_radius' );
const styles = {
backgroundColor: primaryColor || '#007bff' ,
borderRadius: borderRadius || '4px'
};
Emergency Control
// Disable features remotely if issues arise
const chatEnabled = grain . getConfig ( 'chat_enabled' );
if ( chatEnabled !== 'false' ) {
initializeChat ();
}
Auto-Refresh
Configs automatically refresh in the background:
import { GrainTag } from '@grainql/tag' ;
const grain = GrainTag . init ({
tenantId: 'your-tenant-id' ,
configRefreshInterval: 120000 // Refresh every 2 minutes
});
Default is 5 minutes. Set to 0 to disable auto-refresh.
Caching
Configs are cached in localStorage (or memory in Node.js):
import { GrainTag } from '@grainql/tag' ;
const grain = GrainTag . init ({
tenantId: 'your-tenant-id' ,
enableConfigCache: true , // Default
configCacheKey: 'my_app_config' // Custom cache key
});
Why cache? Your app loads instantly with previously fetched values, even offline.
Disable caching if needed:
enableConfigCache : false // Always fetch from API
Managing Configs
Configure values in the Grain dashboard:
Go to grainql.com/dashboard
Navigate to Dashboard > Remote Config
Create configuration keys
Set default values
Add rules for personalization
Publish changes
Changes take effect immediately for all clients.
Next Steps
A/B Testing Guide Build A/B tests with remote config
Feature Flags Guide Implement feature flags
Personalization Create personalized experiences
Config Methods API See all configuration methods