Skip to content
Oxide
Esc
navigateopen⌘Jpreview
On this page

Quickstart

Install the plugin, write a server, and run a production build with Vite or Rsbuild.

Install

npm install -D oxidejs
pnpm add -D oxidejs
yarn add -D oxidejs
bun add -D oxidejs

Extend the TypeScript config:

{ "extends": "oxidejs/tsconfig" }

Add the plugin

Use Vite or Rsbuild. Same plugin, same output.

import { function defineConfig(config: UserConfig): UserConfig (+5 overloads)
Type helper to make it easier to use vite.config.ts accepts a direct {@link UserConfig } object, or a function that returns it. The function receives a {@link ConfigEnv } object.
defineConfig
} from "vite";
import const oxide: (options?: OxidejsOptions | undefined) => import("vite").Plugin<any> | import("vite").Plugin<any>[]oxide from "oxidejs/vite"; export default function defineConfig(config: UserConfig): UserConfig (+5 overloads)
Type helper to make it easier to use vite.config.ts accepts a direct {@link UserConfig } object, or a function that returns it. The function receives a {@link ConfigEnv } object.
defineConfig
({
UserConfig.plugins?: PluginOption[] | undefined
Array of vite plugins to use.
plugins
: [function oxide(options?: OxidejsOptions | undefined): import("vite").Plugin<any> | import("vite").Plugin<any>[]oxide()],
});

Add scripts to package.json:

{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  }
}
import { import defineConfigdefineConfig } from "@rsbuild/core";
import const oxide: (options?: OxidejsOptions | undefined) => anyoxide from "oxidejs/rsbuild";

export default import defineConfigdefineConfig({
  plugins: any[]plugins: [function oxide(options?: OxidejsOptions | undefined): anyoxide()],
});

Add scripts to package.json:

{
  "scripts": {
    "dev": "rsbuild dev",
    "build": "rsbuild build",
    "preview": "rsbuild preview"
  }
}

Write a server entry

export default {
  function fetch(request: Request): Response | undefinedfetch(request: Requestrequest: Request) {
    if (new var URL: new (url: string | URL, base?: string | URL) => URL
The **`URL`** interface is used to parse, construct, normalize, and encode URLs. It works by providing properties which allow you to easily read and modify the components of a URL. [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL)
URL
(request: Requestrequest.Request.url: string
The **`url`** read-only property of the Request interface contains the URL of the request. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/url)
url
).URL.pathname: string
The **`pathname`** property of the URL interface represents a location in a hierarchical structure. It is a string constructed from a list of path segments, each of which is prefixed by a / character. [MDN Reference](https://developer.mozilla.org/docs/Web/API/URL/pathname)
pathname
=== "/api/ok") {
return new var Response: new (body?: BodyInit | null, init?: ResponseInit) => Response
The **`Response`** interface of the Fetch API represents the response to a request. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response)
Response
("ok");
} }, };

Return undefined to fall through to static files. Missing files fall back to index.html only for navigations.

Build and run

vite build
node dist/server.js

No index.html → only dist/server.js. With index.html → client assets in dist/client/. Files in public/ land next to those assets.

Common workflows

celld

celld is a self-hosted alternative to Cloudflare Workers. It is not Cloudflare.

import const oxide: (options?: OxidejsOptions | undefined) => import("vite").Plugin<any> | import("vite").Plugin<any>[]oxide from "oxidejs/vite";

function oxide(options?: OxidejsOptions | undefined): import("vite").Plugin<any> | import("vite").Plugin<any>[]oxide({
  OxidejsOptions.preset?: OxidejsPreset | undefined
"fetch" (default) skips wrangler.jsonc and serves client assets. "celld" emits wrangler.jsonc.
preset
: "celld",
OxidejsOptions.wrangler?: OxidejsWranglerOptions | undefined
Wrangler config fields to merge into the generated wrangler.jsonc.
wrangler
: { OxidejsWranglerOptions.name: stringname: "my-app", OxidejsWranglerOptions.compatibility_date: stringcompatibility_date: "2026-01-01" },
});

preset: "celld" writes dist/wrangler.jsonc and skips asset serving (ASSETS does that). See wrangler.

Server only

Leave out index.html. The plugin emits dist/server.js and does not build a client.

Next steps

Was this page helpful?