newX 1.3 — islands to disk, server-mode islands, image proxy

API Routes

API routes

Build REST endpoints alongside your frontend pages. API routes live in src/api/ and share the same process as your pages.

File-based API routing

Like pages, API routes use the file system. A file at src/api/hello.ts becomes /api/hello. Handlers are plain functions: export the HTTP method you want to handle, receive the Request, return a Response. The Request is the standard fetch API request, so req.json(), req.formData(), and req.headers all work as expected.

src/api/hello.ts
export function GET(req: Request) {  return Response.json({ message: "Hello from x!" });}

Request & response

Each exported HTTP method receives the raw request and returns a standard Response. Dynamic segments work the same as pages: api/users/[id].ts/api/users/:id. Return any Response, including Response.json(...) and new Response(stream).

src/api/users.ts
export async function GET(req: Request) {  const users = await db.query("SELECT * FROM users");  return Response.json(users);}export async function POST(req: Request) {  const body = await req.json();  const result = await db.query(    "INSERT INTO users (name, email) VALUES (?, ?) RETURNING *",    [body.name, body.email],  );  return Response.json(result, { status: 201 });}

POST endpoint example

src/api/contact.ts
export async function POST(req: Request) {  const form = await req.formData();  const email = form.get("email");  const message = form.get("message");  if (!email || !message) {    return Response.json(      { error: "Email and message are required" },      { status: 400 },    );  }  await sendEmail({ email, message });  return Response.json({ success: true });}

API route tree

API routes support the same file-tree conventions as pages: nested folders, dynamic segments, and index files.

file tree
src/api/
hello.ts -> GET /api/hello
users.ts -> GET, POST /api/users
users/
[id].ts -> GET, PUT, DELETE /api/users/:id
auth/
login.ts -> POST /api/auth/login
register.ts -> POST /api/auth/register

Process sharing

API routes run in the same Bun process as your pages and server functions. This means you can share database connections, in-memory caches, and configuration without any network overhead.