Skip to content

Ryware/nona-config

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

134 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Nona — Open Source Firebase Remote Config Alternative

Self-hosted feature flags and remote configuration for web, mobile, and backend apps.

Docker Pulls npm NuGet Chocolatey License: Apache 2.0 OpenSSF Scorecard

Nona gives you the same feature flag and remote config capabilities as Firebase Remote Config — without the Google account, without the lock-in, and running entirely on your own infrastructure.

  • Toggle feature flags from a dashboard without redeploying
  • Update mobile app config (iOS, Android, React Native, Flutter) without an app store release
  • Use kill switches to disable broken features in seconds
  • Fetch everything via one REST API call — no SDK required in any language

🌐 nonaconfig.com  ·  🐳 Docker Hub  ·  📦 npm  ·  📦 NuGet


Table of Contents


Why We Open Sourced Nona

Remote configuration is too often bundled with platform lock-in. We wanted teams to be able to change application behavior quickly without giving up control of their own infrastructure, data ownership, or platform choice.

Nona is our attempt to keep this part of the stack small and understandable: one Docker image, one HTTP API, official clients where they help, and a real migration path away from Firebase Remote Config. The longer story is here: Why we open sourced Nona.


Why Nona

Nona Firebase Remote Config
Open source ✅ Apache 2.0 licence ❌ Closed source
Self-hostable ✅ Docker / Kubernetes ❌ Google-hosted only
No Google account ❌ Required
Works without mobile SDK ✅ Plain HTTP ❌ Firebase SDK needed
.NET / NuGet client
Migration tool ✅ Built into CLI
Free forever ✅ Self-host Free tier with limits

Nona runs as a single Docker container with an embedded libSQL database — no external database, no separate control plane, no cloud dependency.


Quick Start

docker run -d \
  --name nona \
  --restart unless-stopped \
  -p 18080:8080 \
  -v nona-data:/var/lib/nona \
  rywaredev/nona:latest
  • Web UI: http://localhost:18080
  • API base: http://localhost:18080

Create a project, add environments, and set your first key-value pair. Then fetch your config:

curl http://localhost:18080/v1/config/my-app/production \
  -H "X-API-Key: your-api-key"
{
  "checkout_v2": true,
  "dark_mode": false,
  "banner_text": "Hello",
  "max_upload_mb": 50
}

Repository Layout

This repository is the Nona monorepo:

  • core, cli, libsql, migrator: backend API, CLI, storage library, and migration tooling
  • admin: admin web UI
  • client: JavaScript SDK, .NET SDK, and JavaScript OpenFeature provider
  • docs: documentation site

Client Libraries

JavaScript / Node.js / React Native

npm install nona-client
import { createNonaClient } from "nona-client";

const nona = createNonaClient({
  baseUrl: "https://nona.example.com",
  environmentId: "production",
  apiKey: process.env.NONA_API_KEY
});

const value = await nona.getConfigValue("Features:Checkout");
console.log(value.value);

📦 npmjs.com/package/nona-client


.NET / C#

dotnet add package Nona.Client
using Nona.Client;

var client = new NonaClient("https://nona.example.com", "production", apiKey: "your-api-key");
var value = await client.GetConfigValueAsync("Features:Checkout");
Console.WriteLine(value.Value);

📦 nuget.org/packages/Nona.Client


OpenFeature / JavaScript

npm install nona-client nona-openfeature-provider @openfeature/server-sdk

See client/javascript-openfeature-provider/README.md for setup and usage.


Any language (plain HTTP)

No SDK needed. A single GET request returns all config for a project and environment as JSON:

# curl
curl https://your-nona-host/v1/config/{project}/{environment} \
  -H "X-API-Key: your-api-key"

# Python
import httpx
config = httpx.get(
    "https://your-nona-host/v1/config/my-app/production",
    headers={"X-API-Key": api_key}
).json()

# Go
req, _ := http.NewRequest("GET", "https://your-nona-host/v1/config/my-app/production", nil)
req.Header.Set("X-API-Key", apiKey)

CLI (Windows / macOS / Linux)

# Windows via Chocolatey
choco install nona-cli

Or download the binary from GitHub Releases.

🍫 community.chocolatey.org/packages/nona-cli


API

Method Path Description
GET /v1/config/{project}/{environment} Fetch all config for a project/environment
GET /v1/config/{project}/{environment}/{key} Fetch a single key

Authentication: X-API-Key request header.


Docker Compose

Standalone (recommended for most deployments)

Copy deploy/compose/standalone-prod.yml to your server:

docker compose -f standalone-prod.yml up -d

Default host port: http://localhost:18080

Variable Default Description
NONA_API_PORT 18080 Host port mapped to the API
Jwt__Key auto-generated JWT signing key
Jwt__Issuer nona JWT issuer claim
Jwt__Audience nona JWT audience claim

Primary / Replica

For read-heavy workloads or geographically distributed deployments, use deploy/compose/primary-replica-prod.yml:

docker compose -f primary-replica-prod.yml up -d
Service API port libSQL port gRPC port
nona-primary 18081 19080 15001
nona-replica 18082 19082

The replica connects to the primary over gRPC and syncs automatically. Reads served from the replica are 10–15× faster for remote clients (see Performance).

JWT Settings

Nona auto-generates JWT settings on first start. To pin your own values:

docker run -d \
  --name nona \
  -p 18080:8080 \
  -v nona-data:/var/lib/nona \
  -e Jwt__Key=<your-secret-key> \
  -e Jwt__Issuer=nona \
  -e Jwt__Audience=nona \
  rywaredev/nona:latest

Migrate from Firebase Remote Config

The Nona CLI includes a built-in Firebase Remote Config migration command that imports your existing parameters using a migration config file.

# Install CLI
choco install nona-cli

# Run migration
nona migrate firebase \
  --config ./nona.migration.json \
  --base-url http://localhost:18080

See cli/src/Nona.Cli/README.md for the full CLI reference.


Performance

All measurements from production-equivalent environments.

Single-node (libSQL local)

Dataset: 10,000 rows, p95 latency:

Scenario p95 (ms) req/s
Point lookup — 1 key 0.154 11,248
Point lookup — 100 keys 0.712 1,616
Range query — 1,000 rows 3.703 289

All targets pass with 0% error rate under load.

Primary / Replica (remote client)

Scenario Primary p95 Replica p95
1 key, c1 50.0 ms 2.6 ms
100 keys, c1 56.8 ms 6.6 ms
1,000 rows, c1 263.2 ms 42.9 ms

Replica reads are 10–15× faster for geographically distant clients.

Note: Replication is asynchronous. Immediate read-after-write consistency is not guaranteed — replicas are best for read-heavy workloads where eventual consistency is acceptable.


Architecture

┌─────────────────────────────────────┐
│  Nona Container (rywaredev/nona)    │
│                                     │
│  ┌──────────┐   ┌─────────────────┐ │
│  │ Web UI   │   │   HTTP API      │ │
│  │ :8080    │   │   :8080         │ │
│  └──────────┘   └─────────┬───────┘ │
│                           │         │
│                  ┌────────▼────────┐│
│                  │  embedded libSQL││
│                  │  /var/lib/nona  ││
│                  └─────────────────┘│
└─────────────────────────────────────┘
  • No external database — libSQL is bundled in the container image
  • Single port — API and Web UI share port 8080
  • Persistent volume — mount /var/lib/nona to survive container restarts
  • Optional replica — add a read replica with the primary/replica compose file

Contributing

Issues and pull requests are welcome. See the issues tracker to report bugs or request features.


Licence

Apache 2.0 — free to use, self-host, and modify.

Built by Ryware.dev

About

Open-source self-hosted feature flags & remote config — a Firebase Remote Config alternative. One REST API, any language, Docker-first. Apache 2.0.

Topics

Resources

License

Stars

56 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors