---
id: react/quickstart
title: Quickstart
---

Eight steps from empty Vite app to first translated string. Each step links the page that owns the detail.

## 1. Install

```bash
pnpm add @secundus-studio/stift-react@0.4.0 @secundus-studio/stift-vite-plugin@0.4.0
```

Package variants: [Installation](../getting-started/installation.md).

## 2. Wire the Vite plugin

```ts
// vite.config.ts
import { stiftPlugin } from '@secundus-studio/stift-vite-plugin'

export default defineConfig({
  plugins: [
    // ...your existing plugins
    stiftPlugin({ devtools: { allowFileWrites: true } }),
  ],
})
```

`devtools.allowFileWrites: true` mounts the `/__stift_devtools/write` bridge so the panel can persist edits back into `locales/**`. Leave it off unless you're demoing live editing — with the default `false` there is zero code path that can write to disk. Full options: [Build: Vite Plugin & CLI](../tooling/build.md).

## 3. Write the config

```ts
// stift.config.ts
import { defineConfig } from '@secundus-studio/stift-generator'

export default defineConfig({
  locales: { default: 'en', supported: ['en', 'ar'] },
  namespaces: { dir: 'locales', discovery: 'convention', default: ['common'] },
  messageFormat: 'icu-mf1',
  detection: { order: ['explicit', 'custom', 'navigator'], fallback: 'en' },
  loadingStrategy: 'critical-then-full-background',
})
```

Start minimal; add `params.context`, `units`, and `security.tier` once the feature calls for them. Full schema: [stift.config.ts](../configuration/config-file.md).

## 4. Add the first namespace

Create `locales/en/common.json`:

```json
{ "greeting": "Hello, {name}!" }
```

The default locale is the schema — new keys propagate to every other locale automatically. Never hand-sync locale files. Rules: [Messages & Keys](../authoring/messages.md).

## 5. Create the instance

```ts
// src/stift.ts
import { createStiftApp } from '@secundus-studio/stift-react'
import { createStiftRuntime } from 'virtual:stift/runtime'
import { createBestEffortPersister } from '@secundus-studio/stift-persisters'

export const { stift, boot } = await createStiftApp({
  ...createStiftRuntime(),              // generated config + catalog + source
  persister: createBestEffortPersister, // offline packs — see Offline & Persistence
})
```

Everything declarative lives in `stift.config.ts`: detection order (including the reserved `'persisted'` slot) and the `state` block (`{ prefix: '__stift_', storage: 'webStorage' }`) that persists the locale + `setParam`/`setUnit` overrides. The plugin emits two generated artifacts: `src/stift.gen.d.ts` (type augmentation — keys, locales, params become literal types) and `virtual:stift/runtime` (`createStiftRuntime()`). Offline wiring: [Offline & Persistence](../runtime/offline-persistence.md).

## 6. Boot

```tsx
// src/main.tsx
import { stift, boot } from './stift'

await boot() // persisted > navigator > fallback; loads per loadingStrategy

render(
  <StiftProvider stift={stift}>
    <Suspense fallback={<FullPageLoader />}>
      <App />
    </Suspense>
  </StiftProvider>,
)
```

Boot modes (splash, suspense, immediate): [Setup & Boot Modes](../react/setup.md). Loading strategies: [Loading Strategies](../configuration/loading-strategies.md).

## 7. Translate in a component

```tsx
const { t } = useTranslation('common')
t('greeting', { name: user.name })
```

Typos and wrong params are compile errors once the typegen runs. Values, rich text, grammatical agreement: [Translating & Values](../react/translating.md).

## 8. Verify

- `pnpm dev`, open the app: the greeting renders from `locales/en/common.json`.
- Add the devtools panel ([Devtools](../tooling/devtools.md)), switch locale, edit a string: it writes back to disk and the UI updates **in place — no full page reload**. The terminal logs `[stift] devtools write: <locale>/<ns>#<key> -> <file>`.
- Mistype a key in a component: `tsc` fails. That is the whole point.

## Where next?

- Writing real messages (ICU, dialects) → [Messages & Keys](../authoring/messages.md)
- Runtime config, params, units, security tiers → [stift.config.ts](../configuration/config-file.md)
- Making it work offline → [Offline & Persistence](../runtime/offline-persistence.md)
