One Logo Pool Ball
wwwwwwwwwwwwwwwwwww

one build

Building your app for production happens through one build.

It takes the following arguments (see the CLI reference for every command):

Terminal window
npx one build [options]
--platform web|ios|android # what to build (default: web)
--only <pattern> # limit the pages built to a micromatch pattern
--step <name> # run a single internal build step
--skip-env # skip loading .env files during build

To build for iOS for example, you would run:

Terminal window
npx one build --platform ios

Building for web

When building One for web, the output will be a mostly static directory of HTML, CSS, and JavaScript. Internally, One runs a few different Vite production builds to output client, server, and API folders. This output is always in the dist directory.

Ensure your .env file has a ONE_SERVER_URL set to your production URL, like:

ONE_SERVER_URL=https://onestack.dev

After a successful web build, one build --step generate reuses the existing client assets, Vite manifest, and buildInfo.json while rebuilding the server and generating pages. Keep these outputs together. Run a full build first, and run it again when client code or routes change.

We provide a production server based on Hono with one serve that handles loaders, SSR, and API routes for you. You can choose a deploy target for that server. This can be chosen via your Vite configuration:

vite.config.ts
import { one } from 'one/vite'
export default {
plugins: [
one({
web: {
deploy: 'vercel' // defaults to 'node'
}
})
]
}

For detailed deployment instructions, see the Deployment Guide.

If you are only using SPA and SSG routes and aren’t using loaders, you can statically serve the results of dist/client using any server you’d like.

Parallel builds with worker threads

By default, One uses worker threads to build static pages in parallel across multiple CPU cores. This can significantly speed up builds for sites with many pages.

One uses two workers by default, which keeps peak memory low. Set build.concurrency to use more when the machine has memory to spare:

vite.config.ts
import { one } from 'one/vite'
export default {
plugins: [
one({
build: {
concurrency: 4
}
})
]
}

ONE_BUILD_CONCURRENCY overrides the config value for one-off builds:

Terminal window
ONE_BUILD_CONCURRENCY=2 npx one build

You can also disable worker threads entirely through config or an environment variable:

vite.config.ts
one({
build: {
workers: false
}
})
Terminal window
ONE_BUILD_WORKERS=0 npx one build

Security scanning

One automatically scans your client bundles for leaked secrets after building. By default it logs warnings — for production deployments, we recommend setting securityScan to 'error' to fail the build if secrets are found:

vite.config.ts
import { one } from 'one/vite'
export default {
plugins: [
one({
build: {
securityScan: 'error'
}
})
]
}

The scanner detects common API key patterns (Anthropic, OpenAI, Stripe, GitHub, AWS), bearer tokens, and generic secret assignments. See Configuration: build.securityScan for all options.

Building for native

Build the native JS bundle with --platform ios or --platform android. This always runs through the Rolldown path, regardless of your native.bundler dev setting.

To ship to devices, integrate the bundle into the existing native build process. See Build or Run iOS for archiving and uploading.

Or check out the iOS Native Guide for instructions on building your iOS app with Xcode.

Edit this page on GitHub.