building-with-one
One Framework Guide
Official docs: Introduction, Installation, Configuration
One is a full-stack React framework targeting both web and React Native with a single codebase. Built on Vite with file system routing, server-side loaders, and flexible render modes (SSG, SSR, SPA). For native builds, One supports Metro (recommended) and an experimental Vite bundler.
References
Consult these resources as needed:
references/
routing.md File conventions, dynamic routes, groups, parallel routes, intercepting routes, typed routes
layouts.md _layout.tsx, Stack (+ Header Composition API), Tabs, Drawer, Slot, NativeTabs, nested layouts
navigation.md Link (mask, scroll, asChild), useRouter, useLinkTo, Protected, Redirect, route masking
components.md Head (+ iOS Handoff/Spotlight), SafeAreaView, ScrollBehavior, LoadProgressBar, withLayoutContext
hooks.md All hooks: useParams, useSearchParams, useActiveParams, useSegments, useMatches, useBlocker, etc.
configuration.md vite.config.ts, one() plugin options, web/native/global settings, env vars
render-modes.md SSG, SSR, SPA, API per-page and global, folder suffixes, layout render modes
middleware.md _middleware.ts, createMiddleware, auth, CORS, redirects, context sharing
devtools.md Alt+Space spotlight, SEO preview, route debug, loader timing, source inspector, input recording
Quick Start
npx one
This scaffolds a new project with starter templates. Then:
bun install
bun run dev
Access at http://localhost:8081. For native, use Expo Go or build with one prebuild and one run:ios.
Project Structure
app/
_layout.tsx Root layout (Stack, Tabs, Drawer, or Slot)
_middleware.ts Server middleware (optional)
index.tsx Home route (/)
about.tsx Static route (/about)
blog/
[slug].tsx Dynamic route (/blog/:slug)
_layout.tsx Nested layout
dashboard+spa/ SPA folder (all children are SPA)
index.tsx
api/
route+api.ts API endpoint (/api)
users/[id]+api.ts Dynamic API route
+not-found.tsx 404 page
vite.config.ts One configuration
app/routes.d.ts Auto-generated route types
Key Rules
- Routes live in the
app/directory only - Never co-locate components, types, or utilities in
app/— keep them insrc/,components/, etc. - Always have a route that matches
/(even inside a group route) - Use
_layout.tsxfor layouts — it must render<Slot>,<Stack>,<Tabs>, or<Drawer> - Use
+api.tssuffix for API routes, not regular route files - Platform-specific files:
.web.tsx,.native.tsx,.ios.tsx,.android.tsx— never import these directly, the bundler resolves them - Pin the
oneversion for production stability
CLI
one dev [--clean] [--host] [--port] [--debug] # dev server (web + native)
one build [web | ios | android] # production build
one serve [--cluster] [--port] # production server (Hono)
one prebuild # generate native Xcode/Android projects
one run:ios # build and run iOS app
one run:android # build and run Android app
one generate-routes [--typed=runtime|type] # regenerate route types
one patch [--force] # apply package patches
Configuration
All config goes through the Vite plugin in vite.config.ts:
import { one } from 'one/vite'
export default {
plugins: [
one({
web: {
defaultRenderMode: 'ssg',
deploy: 'node', // 'node' | 'vercel' | 'cloudflare'
linkPrefetch: 'intent', // trajectory-based prefetching
sitemap: true,
},
native: {
bundler: 'metro', // recommended for stability
},
}),
],
}
See ./references/configuration.md for all options.
Running the App
Web:
one dev
Native with Expo Go (recommended for quick iteration):
one dev
# press q, r in terminal to show QR code
# scan with Expo Go app
Native with custom build (for custom native dependencies):
one prebuild
one run:ios # or one run:android
Production:
ONE_SERVER_URL=https://myapp.com one build
one serve --cluster # cluster mode for high traffic
Code Style
- Use
process.env.EXPO_OSinstead ofPlatform.OSfor platform checks - Use
import.meta.env.VITE_ENVIRONMENTfor environment checks ('client', 'ssr', 'ios', 'android') - Prefix client-exposed env vars with
VITE_,EXPO_PUBLIC_, orONE_PUBLIC_ - Add
/// <reference types="one/env" />to a.d.tsfile for typed env vars - Use
createRoute<'/path/[param]'>()for fully typed route params and loaders
Routing Exports
Route files support special exports:
// loader — server-side data fetching (tree-shaken from client)
export async function loader({ params, path, request }) { ... }
// generateStaticParams — expand dynamic SSG routes at build time
export async function generateStaticParams() { return [{ slug: 'hello' }] }
// sitemap — control sitemap.xml entry for this route
export const sitemap = { priority: 0.8, changefreq: 'daily', exclude: false }
Devtools
In development, press these shortcuts:
| Shortcut | Panel |
|---|---|
Alt+Space |
Spotlight menu |
Alt+S |
SEO Preview |
Alt+R |
Route Debug |
Alt+L |
Loader Timing |
Alt+P |
Route Preload |
Alt+E |
Error Panel |
Environment Variables
| Variable | Value |
|---|---|
VITE_ENVIRONMENT |
'client', 'ssr', 'ios', 'android' |
VITE_NATIVE |
'1' on native, '' on web |
EXPO_OS |
'web', 'ios', 'android' |
ONE_SERVER_URL |
Auto in dev, set manually in prod |
ONE_CACHE_KEY |
Per-build random key |
Client-safe prefixes: VITE_*, EXPO_PUBLIC_*, ONE_PUBLIC_*.
Platform Support
- Web: Browser via Vite
- iOS: React Native via Metro (recommended) or Vite
- Android: React Native via Metro (recommended) or Vite
- Not supported: Windows, Bun runtime for development
More from onejs/skills
one-deployment
Deploy One framework apps to Node servers, Vercel, Cloudflare Workers, or as static sites. Covers build, serve, cluster mode, security scanning, and platform-specific configuration.
1one-guides
Guides and recipes for One framework. Covers authentication, images, CSS optimization, dark mode, Tamagui, MDX, OpenGraph images, ISR, skew protection, native iOS builds, EAS, CRA migration, and common issues.
1one-loaders
Server-side data loading in One framework. Use when fetching data for pages, implementing caching, redirects, response headers, ISR, refetching, or file-driven content with loaders.
1