Getting Started
Self-host Unleash with Docker Compose, integrate from a Node app, and evaluate your first flag
Getting Started
Unleash is a strong starting point — open-source, self-hostable, with an OpenFeature-compatible SDK. This page boots Unleash locally, creates a flag, and integrates from a Node.js app.
The patterns transfer to LaunchDarkly, Flagsmith, ConfigCat, and others — only the SDK names change.
Bring Up Unleash
# docker-compose.yml
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: unleash
POSTGRES_USER: unleash
POSTGRES_PASSWORD: unleash
volumes:
- unleash-pg:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U unleash"]
interval: 5s
retries: 10
unleash:
image: unleashorg/unleash-server:6
ports:
- "4242:4242"
environment:
DATABASE_HOST: postgres
DATABASE_NAME: unleash
DATABASE_USERNAME: unleash
DATABASE_PASSWORD: unleash
DATABASE_SSL: "false"
INIT_ADMIN_API_TOKENS: "*:*.unleash-insecure-admin-key"
INIT_CLIENT_API_TOKENS: "default:development.unleash-insecure-api-key"
depends_on:
postgres:
condition: service_healthy
volumes:
unleash-pg:docker compose up -d
open http://localhost:4242
# default login: admin / unleash4allCreate a Flag in the UI
In the Unleash UI:
- Navigate to Default → Feature flags → New feature flag.
- Name it
new-checkout, type Release, project Default. - Save. The flag exists but isn't enabled in any environment yet.
- Click into the flag, find the Development environment, click Enable with the default strategy "Standard" (which is "on for everyone").
Integrate from a Node App
npm install unleash-client// app.js
const { initialize } = require('unleash-client');
const unleash = initialize({
url: 'http://localhost:4242/api/',
appName: 'demo-app',
customHeaders: { Authorization: 'default:development.unleash-insecure-api-key' },
});
unleash.on('ready', async () => {
// Simple check
if (unleash.isEnabled('new-checkout')) {
console.log('new checkout is on');
} else {
console.log('new checkout is off');
}
// With context (user, country, etc.)
const ctx = { userId: 'user-42', properties: { country: 'US' } };
console.log('per-user:', unleash.isEnabled('new-checkout', ctx));
});node app.jsThe SDK polls the Unleash API every 15 seconds (configurable) and caches the result in memory. Flag evaluation is local — no network call per check.
Add a Targeting Rule
Back in the UI, edit the flag's Development environment:
- Strategies → Edit → Gradual rollout.
- Set Stickiness to
userId, Rollout % to25. - Save.
Now unleash.isEnabled('new-checkout', { userId: 'user-42' }) will return true for ~25% of stable user IDs — and consistently for the same user.
Try with different user IDs:
for (let i = 1; i <= 20; i++) {
const ctx = { userId: `user-${i}` };
console.log(`user-${i}: ${unleash.isEnabled('new-checkout', ctx)}`);
}You'll see roughly 25% true — and user-1 always gets the same answer. That's deterministic bucketing; the same user always sees the same variant on repeat visits.
Server-Side vs Client-Side SDKs
| Server-side | Client-side | |
|---|---|---|
| Where evaluation runs | In your backend process | In the browser / mobile app |
| Flag definitions | Full ruleset fetched | Only what's needed for this user |
| User identity | Your auth context | The end user |
| Latency cost | Zero (in-process) | A few ms (initial fetch) |
| Security | Definitions are private | Definitions exposed to the client |
For UI flags reachable by users, use a server-side gateway (Unleash Edge / a backend endpoint) that exposes only that user's flag values — don't ship the whole ruleset to browsers.
OpenFeature: Vendor-Neutral
For new code, prefer the OpenFeature SDK so swapping vendors later is a one-file change:
npm install @openfeature/server-sdk @openfeature/unleash-providerconst { OpenFeature } = require('@openfeature/server-sdk');
const { UnleashProvider } = require('@openfeature/unleash-provider');
await OpenFeature.setProviderAndWait(new UnleashProvider({
url: 'http://localhost:4242/api/',
appName: 'demo-app',
customHeaders: { Authorization: 'default:development.unleash-insecure-api-key' },
}));
const client = OpenFeature.getClient();
const enabled = await client.getBooleanValue('new-checkout', false, {
targetingKey: 'user-42',
country: 'US',
});The same code works against LaunchDarkly, Flagsmith, ConfigCat, etc. by swapping the provider. Highly recommended for any new project.
Useful CLI Commands
Unleash has a CLI for scripting; most platforms also have an HTTP API:
# Toggle a flag via the admin API
curl -X POST \
-H "Authorization: *:*.unleash-insecure-admin-key" \
-H "Content-Type: application/json" \
http://localhost:4242/api/admin/projects/default/features/new-checkout/environments/development/offSame for on, strategies/add, strategies/update. Use this to script flag changes from CI or from incident-response playbooks.
Tear Down
docker compose down -vWhat's Next
You can evaluate flags from a real app. Next:
- Patterns — targeting rules, gradual rollout, kill switches, A/B testing
- Best Practices — managing flag debt, evaluation latency, fail-safe defaults