Bunext is a Next.js-inspired framework designed for the Bun runtime, providing high-performance SSR, CSR, static site generation, and multi-threaded HTTP workers. It is optimized for modern development workflows with built-in SQLite support, session management, and server actions.
- Bun Version:
1.1.0 - 1.2.15 - Supported OS: Linux, WSL (Windows support in progress)
- Note: Bun is evolving rapidly. New versions may cause compatibility issues. Watch for breaking changes before version
1.0.0.
To install Bunext, use:
bun i bunext-js
bun bunext init
# OR
bun create bunext-appThen initialize your project:
bun run db:create # Creates types and missing tables in the database To start the development server:
bun run dev For production builds:
bun run build
bun run start β
Multi-threaded HTTP workers (Linux only)
β
SSR (Server-Side Rendering) & CSR (Client-Side Rendering)
β
Server & client environment variables (process.env)
β
React 18 & 19 support
β
Static assets & SVG support
β
Server components ("use server" & "use client")
β
Revalidation & caching
β
Session management (public & private)
β
SQLite database management
β
Hot reload in development mode
β
Production-ready mode (Beta)
Bunext follows Next.js-style file-based routing.
src/pages/index.tsxβ Home Pagesrc/pages/[id].tsxβ Dynamic route (/page/123)src/pages/layout.tsxβ Layout for subroutessrc/pages/[segment]/[id].tsxβ Dynamic route and segments (/user/10)
// src/pages/index.tsx
export default function HomePage() {
return <h1>Welcome to Bunext!</h1>;
}// src/pages/[id].tsx
export async function getServerSideProps() {
//server side
return { foo: "bar" };
}
export default function DynamicPage({
params,
props
} : {
params: { id: string },
props: { foo: string }
}) {
return <h1>Page ID: {params.id} {props.foo}</h1>;
}Bunext supports Server Components, which run only at build time and are re-executed only when revalidate() is triggered.
- Any exported function without the
"use client"directive is treated as a Server Component. - Must have no props.
- Must be exported (not inline) and can be
async. revalidate()will re-run all Server Components used on the page.- Must not have hooks
// index.tsx
export default async function Page() {
return (
<div>
{await Components()}
<NotValid />
</div>
);
}
// β
Valid Server Component
export async function Components() {
const res = await (await fetch("https://some-api.com/api")).json();
return <div>{JSON.stringify(res)}</div>;
}
// β Invalid - has props
export function NotValid({ someProps }: { someProps: string }) {
return <div>{someProps}</div>;
}π§© Nested Server Components You can also compose Server Components by nesting them.
// index.tsx
export default async function Page() {
return (
<main>
{await Parent()}
</main>
);
}
export async function Parent() {
return (
<section>
<h2>Parent Component</h2>
{await Child()}
</section>
);
}
export async function Child() {
const data = await (await fetch("https://some-api.com/stats")).json();
return <pre>{JSON.stringify(data, null, 2)}</pre>;
}π Revalidating Components Bunext allows scheduled and manual revalidation.
β± Scheduled Revalidation
// index.tsx
import { revalidate } from "bunext-js/features/router/revalidate.ts";
export default function Page() {
revalidateEvery("/", 3600); // revalidate this page every hour
return (
<div>
<button onClick={() => ServerRevalidate(["/"])}>Revalidate / path</button>
</div>
);
}
π Manual Revalidation
import { revalidate } from "bunext-js/features/router/revalidate.ts";
export async function ServerRevalidate(...paths: string[]) {
revalidate(...paths);
}π Rules to apply
- β Keep Server Components pure β no side effects.
- β Fetch data server-side with async/await.
- β Avoid using props.
- β Don't mutate state or use hooks like useState or useEffect.
You can cache pages for better performance using "use static".
"use static"; // Enables static page caching
export async function getServerSideProps() {
return { data: await fetch("https://api.example.com").then((res) => res.json()) };
}
export default function Page({ props }: { props: { data: any } }) {
return <div>Data: {JSON.stringify(props.data)}</div>;
}Revalidate static pages after a set time:
"use static";
import { revalidateStatic } from "bunext-js/router";
export async function getServerSideProps({request}: {request: Request}) {
revalidateStatic(request, 3600) // revalidate after 1 hour
return { data: await fetch("https://api.example.com").then((res) => res.json()) };
}
export default function Page({ props }: { props: { data: any } }) {
return <div>Data: {JSON.stringify(props.data)}</div>;
}Revalidate static pages in an Action:
import { revalidateStatic } from "bunext-js/router";
export async function ServerRevalidateStaticPage(path: string) {
// path ex: /page/345 ( /page/[id] )
revalidateStatic(path);
}Bunext provides two ways to navigate between pages:
import { navigate, Link } from "bunext-js/internal/router";
function NextPage() {
return (
<>
<button onClick={() => navigate("/new/location")}>Go to New Page</button>
<Link href="/new/location">
<button>Next Page</button>
</Link>
</>
);
}Define HTTP method handlers in files under src/pages to automatically create API endpoints.
import type { BunextRequest } from "bunext-js/internal/server/bunextRequest.ts";
export function POST(request: BunextRequest) {
request.response = new Response("POST");
return request;
}
export function GET(request: BunextRequest) {
request.response = new Response("GET");
return request;
}
export function PUT(request: BunextRequest) {
request.response = new Response("PUT");
return request;
}
export function DELETE(request: BunextRequest) {
request.response = new Response("DELETE");
return request;
}You can send requests to this API using the native fetch function:
await fetch("https://my.site.com/api/v1", {
method: "POST",
body: JSON.stringify({ foo: "bar" })
});
// Response will be: "POST"- Fully typed request with
BunextRequest - Auto-routing based on file path
- Clean, REST-like interface using standard HTTP verbs
Bunext supports server-side and client-side session management.
import { GetSession } from "bunext-js/features/session";
export async function ServerSetSession({ username }) {
const session = GetSession(arguments);
session.setData({ username }, true); // Accessible on both client & server
}import { useSession } from "bunext-js/features/session";
export default function UserStatus() {
const session = useSession();
return <span>{session.getData()?.username || "Not logged in"}</span>;
}export async function ServerDeleteSession() {
GetSession(arguments).delete();
}Bunext supports Server Actions for secure API calls.
- function name must start with the keyword Server
- File & File[] must be at the first level of params.
- formData is supported without other params
- params must be serializable
export async function ServerUploadFile(file: File, data: string) {
await Bun.write(`uploads/${file.name}`, file);
console.log(data);
return { success: true, message: "File uploaded!" };
}Call this function from a client component:
<form action={async (e) => await ServerUploadFile(e.get("file") as File, "picutre") }>
<input type="file" name="file" />
<button type="submit">Upload</button>
</form>import { DBSchema } from "bunext-js/database/schema";
const schema: DBSchema = [
{
name: "Users",
columns: [
{ name: "id", type: "number", unique: true, primary: true, autoIncrement: true },
{ name: "username", type: "string", unique: true },
{ name: "role", type: "string", union: ["admin", "user"] },
],
},
];
export default schema;Run the migration:
bun run db:createimport { Database } from "bunext-js/database";
const db = Database();
const users = db.Users.select({ where: { role: "admin" } });PUBLIC_API_KEY="123456"β Accessible in client & serverAPI_KEY="private-key"β Only accessible in server
Use in code:
console.log(process.env.PUBLIC_API_KEY); // Available in client
console.log(process.env.API_KEY); // Server-onlyExperimental
Import module from directory you don't want to explicitly add to your code. Exemple: templates, you does not want to import every of them,
In config/server.ts add
const Config: ServerConfig = {
HTTPServer: {
port: 3010,
},
Dev: {
hotServerPort: 3005,
},
session: {
type: "database:hard",
},
router: {
dynamicPaths: ["src/dynamic"], // base paths of dynamic components
},
};"use client";
export function getServerSideProps() {
// make a Glob of files or get from the Database
return {
template_name: "component_1"
}
}
export default async function DynamicImport({props}:{props: {template_name: string}}) {
return (
<Bunext.plugins.onRequest.components.DynamicComponent
pathName={`/src/dynamic/${props.template_name}`}
elementName="default"
props={{ title: "foo-bar" }}
/>
);
}
// /src/dynamic/:template_name
export default function DynamicComponent({ title }: { title: string }) {
return (
<div>
<h1>{title}</h1>
<h1>Dynamic Component</h1>
<p>This component is loaded dynamically.</p>
</div>
);
}
Bunext is optimized for speed and efficiency.
Contributions are welcome! Submit issues and PRs on GitHub.
Bunext is open-source under the MIT License.
This version improves readability, adds more examples, and organizes the content better. Let me know if you want any changes! π
π’ 0.8.18
- Fix Database schema union type making number as string
- Database schema in JSON objects in arrays are considered unions
- Database schema union in JSON column type can be string or/and number
- Session strategy has changed and session timeout is automatically updated
- Database
LIKEoperator forSELECToperation - Direct access to the database for making custom requests (must be secured manually)
- Added tests for database
- Automatic session timeout update UI
π’ 0.8.19
- Enforce tests
- Remove unused files in build after each build
- Router:
[segmentName].tsxis now supported- Previously: Only
[id].tsxwas supported - Now: Any
[segmentName]is supported (e.g.,[foo].tsx,[bar].tsx)
- Previously: Only
- Update README
- SVG loader now uses SVGR (stable)
π’ 0.8.20
- Caching SVG for a more fluid development experience
π’ 0.8.21
- Update SVG caching strategy for cold start improvement and cache validation based on file hash
- New caching system for SSR Elements
- Fix a long-time bug where builds crashed when Server Components list was too large
- Improve build speed
- Added Single-Threaded & Multi-Threaded Benchmarks in README
π’ 0.8.22
- Fix missing regex for
[segmentName] - Fix Concurrent Read & Write of the Database
- Add utility functions to generate fake data
- Cache is cleared in the browser between dev versions
π’ 0.8.23
- Fix crash in dev mode introduced in Bun version
1.1.43
π’ 0.8.24
- Fix crash with the dev client WebSocket
- Fix Layout not working if inside a dynamic segment directory
π’ 0.8.26
- Fix Layout not rendering when inside a dynamic segment directory and the request does not use the client-side router (direct access)
- Parallelized layout imports to reduce cold start & dev mode loading times
πΉ 0.9.x Versions
π’ 0.9.0
- Removed unused code β Performance upgrade
- CSS is now automatically imported into the
<head>component
π’ 0.9.2
- Fix Session not updating when modified outside an event
- Fix all TypeScript errors
- Fix false errors when compiling in dev mode with SSR component caching
- Dynamically update
<Head>withuseHead - Added explicit exports β Projects may need to update imports
Headdata can be dynamic. Request object is parsed as props to the page element (default export of index.tsx)- Direct access to the
requestobject from any component running on the server - Dev builds are now more verbose and cleaner
π’ 0.9.3
- Fix CSS auto-imports for dynamic segments
- Auto-imported CSS is rendered at first load, suppressing flickering on direct access or first load
π’ 0.9.4
- Fix CSS not imported on direct access for CSS inside a
Pageelement (worked for layouts) - SVG and CSS files are now typed correctly
- NEW FEATURE:
"use static"directive- Caches pages for specific paths (even with dynamic segments)
- Example:
/a/path/[id]caches/a/path/1and/a/path/2 - Can be revalidated
- Router code cleaned
- Stronger fetch caching
π’ 0.9.6
"use static"performance upgrade- Routes exporting
defaultverified as SSR elements are now cached properly- 80%+ performance boost (significantly reduces server load)
- New 0.8.x vs 0.9.5 benchmark
- Fix "use static" not caching for dynamic segments
- Dynamic pages now have a 100% performance upgrade (no joke)
"use static"benchmark added
π’ 0.9.7
- Fix
getServerSidePropsbreaking when returningundefined - Fix update issue where it overwrites existing React & React-DOM
- Default React & React-DOM versions updated to
19.0.0
π’ 0.9.8
- Override session expiration using
session.setExpiration() - Fix params not reaching
getServerSideProps
π’ 0.9.10
- Added more tests to prevent previous errors from recurring
- Fix
getServerSidePropsbreaking request whenundefinedon route change/refresh in dev mode - Faster development mode reducing build time exponentially
π’ 0.9.16
- Fix Dev mode Reloading page on every file modification.
- adding code rabbit review
- Fix page wasn't reloading after a file change if it wasn't the index or layout
π’ 0.9.17
- Redirection is now possible in a ServerAction
- Fix regression API Endpoint cannot be reach introduced in 0.9.10
π’ 0.9.18
- New Global object Bunext for every Bunext features
- Dynamic Module loading feature. ( Load Module without knowing the name at first ). Exemple will follow + tooling, components
- HTTPServer options can be set from the config file config/server.ts
πΉ0.10.x
π’ 0.10.1
- Update Global Bunext object
- Refactor many components
- dynamic components method change ( only needs to add the server config )
- cleanup code for readability and maintainability
π’ 0.10.3
- Fix regression introduced in 0.9.18 where the onRequest file was not imported correctly
- much more verbose CLI outputs and automatic benchmarking
π’ 0.10.4
- Add a plugin system for altering the life cycle of the build, request and routing process
- Bunext global object updated
πΉ0.11.x
π’ 0.11.1
- Build process worker thread (improve build time by removing the overhead of triggering a new process each time)
π’ 0.11.3
- Upgraded Version of Link element now is a Anchor element and ctrl+click will open in a new tab.
- Link and navigate has typeSafe route path
- BunextPlugin has onFileSystemChange new key (doc will follow)
- update Doc for missing section API endpoints and server components
- Head component for setting dynamic head data
π’ 0.11.4
- Fix minor init type
- Upgrade typed Route paths
- other minor improvement
π’ 0.11.5
- Fix useSession hook not updating properly after a ServerAction modify the session.
- fix typo in CLI
- remove unnecessary getSession props
- fix dev mode serverAction and serverComponents not transpiling correctly
π’ 0.11.6
- fix cli missing NODE_ENV
- add chrome dev tool protocol for workspace
- refactored server-actions and server-components, moved in a plugin format

