Skip to content
rifleDB
Docs: Setup & download

Setup & download

The SDK for your app, the server with its folder config, and Redis for production: what you need, and how to start each piece.

npm release coming. rifledb and @rifledb/server are not on the npm registry yet. The install commands below are the ones that will work once they are. Until then, both run from the rifleDB source workspace, where apps depend on "rifledb": "workspace:*".

Requirements

Node.js
22 or newer. The Docker images run Node 24.
Redis
7 or newer in production, with append-only persistence. In development the server can keep everything in memory instead.
React
19 or newer, for rifledb/react and rifledb/next. The core client needs no React and runs in browsers and in Node.

Install the SDK

shell
npm install rifledb

One package with four entry points:

rifledb
The realtime client: createRifle with its cache, optimistic writes, offline queue and device keys, plus createHttpClient for signed REST.
rifledb/react
RifleProvider and the hooks: useRifle, useFolder, useAction, useEvent, usePresence, useIdentity, useStepUp, useConnection, and createRifleHooks for typed paths.
rifledb/next
RifleHydrate: seeds values fetched on the server, so the first paint matches and the hooks take over live.
rifledb/next/server
createRifleServer: server-only, signed REST with a service key, and snapshotFor for hydration.

Connect an app

Both examples count clicks at playground/counter, a key of the sandbox folder the server ships with, so they work against a fresh development server. Open the page in two tabs and click: both counters move.

src/main.tsx
import { createRoot } from 'react-dom/client'
import { createRifle } from 'rifledb'
import { RifleProvider, useRifle } from 'rifledb/react'

const rifle = createRifle({ url: 'http://localhost:4000' })

function Counter() {
  const [count, api] = useRifle('playground/counter')
  return <button onClick={() => api.inc()}>Clicked {count ?? 0} times</button>
}

createRoot(document.getElementById('root')!).render(
  <RifleProvider client={rifle}>
    <Counter />
  </RifleProvider>,
)

Vite serves on localhost:5173, one of the origins a development server accepts.

Run the server

The server is one Node.js process that serves REST, server-sent events and WebSocket on one port. @rifledb/server comes to npm together with the SDK; today it runs from the workspace.

Declare your folders

Folders live in server/rifle.config.tsx. It is JSX, but nothing renders: each element is plain data the server loads at boot. Add yours inside <Rifle>, next to the folders it ships with.

server/rifle.config.tsx
import { Folder, Rifle, Users } from '@rifledb/server'

export default (
  <Rifle>
    <Users registration='open' />
    {/* … the folders it ships with: system (admin), playground, demo … */}
    <Folder path='polls' mode='public' publicWrite />
    <Folder path='boards' mode='private' />
    <Folder path='rooms' mode='public' publicWrite fast={{ persist: false, ttlMs: 15_000 }} />
  </Rifle>
)

Modes, keys, grants, actions and fast folders: Access control.

Start it

shell
pnpm install
pnpm -F @rifledb/server dev       # http://localhost:4000, data in memory (gone on restart)

# with Redis, so data survives restarts (needs redis-server on your PATH)
pnpm redis:dev                    # Redis on port 6380, append-only file in .data/redis
REDIS_URL=redis://localhost:6380 pnpm -F @rifledb/server dev

For production, build the bundle and start it with the settings of your domain:

shell
pnpm -F @rifledb/server build     # bundles server/dist/main.js

REDIS_URL=redis://localhost:6379 \
RIFLE_PUBLIC_ORIGIN=https://db.example.com \
RIFLE_ALLOWED_ORIGINS=https://app.example.com \
pnpm -F @rifledb/server start     # node dist/main.js

The settings that matter most:

VariableExampleWhat it does
REDIS_URLredis://redis:6379Redis to store everything in. Without it: the in-memory store.
RIFLE_PUBLIC_ORIGINhttps://db.example.comThe origin clients reach the server at. Part of every socket sign-in.
RIFLE_ALLOWED_ORIGINShttps://app.example.comBrowser origins that may connect. The default allows only the local development ports.
RIFLE_WEBAUTHN[{"rpID":"app.example.com", …}]Passkey relying parties. Needed for step-up (secret folders, admin changes) on your own domain.
RIFLE_TRUST_PROXY172.18.0.0/16The network of your reverse proxy, so rate limits see each visitor’s own address.
RIFLE_PORT4000Listening port (default 4000).

Every variable, rate limits, backups and metrics: Operations.

Docker Compose

deploy/Dockerfile.server builds the server image: Node 24, the bundled server, and a health check on /v1/_/health. This file runs it next to Redis. Save it in the workspace root:

rifle.compose.yml
# rifle.compose.yml, in the root of the rifleDB workspace
services:
  redis:
    image: redis:8-alpine
    restart: unless-stopped
    # append-only file, fsync every second
    command: ['redis-server', '--appendonly', 'yes', '--appendfsync', 'everysec']
    volumes:
      - redis-data:/data
    healthcheck:
      test: ['CMD', 'redis-cli', 'ping']
      interval: 10s
      timeout: 3s
      retries: 5

  server:
    build:
      context: .
      dockerfile: deploy/Dockerfile.server
    restart: unless-stopped
    init: true
    stop_grace_period: 20s # a clean shutdown flushes pending writes (up to 15 s)
    depends_on:
      redis:
        condition: service_healthy
    environment:
      REDIS_URL: redis://redis:6379
      RIFLE_PUBLIC_ORIGIN: https://db.example.com
      RIFLE_ALLOWED_ORIGINS: https://app.example.com
      RIFLE_WEBAUTHN: '[{"rpID":"app.example.com","rpName":"My app","origins":["https://app.example.com"]}]'
      # RIFLE_TRUST_PROXY: 172.18.0.0/16   # the network your reverse proxy connects from
    ports:
      - '4000:4000'

volumes:
  redis-data: {}
shell
docker compose -f rifle.compose.yml up -d --build
curl http://localhost:4000/v1/_/health     # {"ok":true,…,"store":"redis","healthy":true,…}

The server speaks plain HTTP: put a reverse proxy with TLS in front of it, and set RIFLE_TRUST_PROXY to the network the proxy connects from, so rate limits apply per visitor. The full production stack (the server, Redis, this site and the admin app behind nginx-proxy) is deploy/docker-compose.yml, with a step-by-step guide in deploy/README.md.

First admin

While no admin exists, the server prints a one-time setup token when it starts: valid 60 minutes, single use, a new one after each restart.

shell
docker compose -f rifle.compose.yml logs server | grep -A 8 'rifleDB admin setup'

Open the admin app’s sign-in page, choose “I have a setup token”, paste it and create the passkey the browser offers. The admin app is a Next.js app in the same workspace: pnpm -F @rifledb/admin dev serves it on localhost:3001, and deploy/Dockerfile.next builds it for production. Its origin must be in RIFLE_ALLOWED_ORIGINS and RIFLE_WEBAUTHN. Once your admin and passkey exist, set RIFLE_ADMIN_SETUP=off.