@lamstack/react-initializer
A lightweight application-startup orchestrator for React. <Initializer> runs a sequence
of stages — a task, or several running concurrently via parallel([...]) — before
rendering your app, with retry, timeout, and critical/non-critical failure handling built
in. The task runner has no React dependency; the React layer is a thin adapter on top of
it.
Pre-1.0 (0.x): the API may still change between minor versions. See
Non-goals below for what this library deliberately doesn’t do.
pnpm
pnpm add @lamstack/react-initializerLive demo
Three stages: config runs first, then auth (critical — its failure aborts the whole
run), then a parallel([...]) stage of profile/cache/translations — since auth is
a stage of its own, that whole third stage simply never starts if auth fails.
translations is marked critical: false and always fails on its own — try it with the
checkbox off to see a non-critical failure recorded without blocking the app (in a real
app you’d fall back to a default locale here).
Preview
Quickstart
The minimal version — no custom splash/error UI, no parallel(), just tasks in order:
import { Initializer, useInitializer } from '@lamstack/react-initializer';
import type { InitializationTask } from '@lamstack/react-initializer';
const initializeConfig: InitializationTask = {
id: 'config',
run: async ({ state }) => {
state.set('config', await loadConfig());
},
};
const initializeAuth: InitializationTask = {
id: 'auth',
retry: 3,
run: async () => {
await restoreSession();
},
};
function App() {
return (
<Initializer tasks={[initializeConfig, initializeAuth]}>
<Dashboard />
</Initializer>
);
}
function Dashboard() {
const { retry } = useInitializer();
return <button onClick={retry}>Reload app</button>;
}<Initializer> withholds children until every task has settled: it renders a splash
screen while tasks run, and an error screen if a critical one fails. Both are plain,
overridable defaults — pass your own splashScreen/errorScreen components, as the demo
above does, to replace them.
- Concepts — the stage model, critical vs non-critical failures,
retry/timeout,
condition, sharedstate, and the rendering contract. - API reference —
InitializationTask,parallel(),<Initializer>props,useInitializer(), and the framework-independentcreateInitializer(). - Testing — how to test components that call
useInitializer(), and the task runner in isolation.
Non-goals
@lamstack/react-initializer does exactly one thing: run a sequence of async startup steps
before rendering the app. It is deliberately not:
- A data-fetching layer. No caching, no request deduplication, no revalidation. Fetch
in
run, store the result instateif a later stage needs it, and use a real data-fetching library for anything your app needs after startup. - A background job scheduler. Tasks run once, during the one run a
<Initializer>instance (orcreateInitializer()call) drives — there’s no recurring/scheduled execution. - A general dependency-graph runner. Ordering is exactly two levels: the stage list,
and
parallel([...])within a stage. There is nodependsOn, no cross-stage edges, and no cycle detection to speak of, because there’s no graph to have a cycle in. - SSR/Suspense-integrated, and it has no cross-reload caching — every mount (or
retry()) is a fresh run, freshstate, freshAbortController.
If you need any of the above, reach for a purpose-built tool instead and hand its result
to a state.set(...) call from within a task.