Server Utilities

View as Markdown

Utilities available from neutron. These should generally only be used in loader and action functions.

redirect

Throws a redirect response.

import { redirect } from "@neutron-build/core";

export async function action() {
  throw redirect("/login");
}

Response Helpers

Neutron uses standard Response objects. You can construct them directly.

export async function loader() {
  if (!found) {
    throw new Response("Not Found", { status: 404 });
  }
}

Keeping code server-only

Two conventions keep server code out of the browser bundle:

.server.ts files

Any module whose filename ends in .server (e.g. db.server.ts, auth.server.ts) is server-only. Its imports are stripped from the client build, so it is safe to use secrets, database drivers, or Node built-ins there:

// src/lib/db.server.ts
import { Pool } from "pg";
export const db = new Pool({ connectionString: process.env.DATABASE_URL });
// src/routes/users.tsx
import { db } from "../lib/db.server.ts"; // stripped from the client bundle

export async function loader() {
  return { users: (await db.query("SELECT * FROM users")).rows };
}

Node built-ins in route modules

You can import Node built-ins (node:fs, path, crypto, …) directly in a route module as long as you only use them in server exports (loader, action, HTTP handlers). When Neutron builds the client half of the route it removes those exports and their now-unused built-in imports, so they never reach the browser:

import { readFileSync } from "node:fs"; // removed from the client bundle

export const config = { mode: "app" };

export async function loader() {
  return { version: readFileSync("VERSION", "utf8") };
}

export default function Page({ data }) {
  return <p>Version {data.version}</p>;
}

Look-alike packages that are not built-ins (fs-extra, path-browserify) are left untouched — only real Node built-ins are stripped.