1import * as Namespace from "../../Namespace.ts";
2import { makeFrameworkSite, type FrameworkSiteProps } from "./FrameworkSite.ts";
3
4/**
5 * The Next.js Node framework module (it is its own deploy target — not
6 * OpenNext). Container-optimal path is `next build` + a long-running Node
7 * process.
8 */
9export const NEXTJS_FRAMEWORK_SPECIFIER =
10 "@alchemy.run/frontend-frameworks/nextjs/node";
11
12/** The Node container deploy target for the Next.js build. */
13export const NEXTJS_NODE_TARGET_SPECIFIER =
14 "@alchemy.run/frontend-frameworks/nextjs/node";
15
16export interface NextjsProps extends FrameworkSiteProps {}
17
18/**
19 * Deploy a Next.js application to Railway as a long-running Node process:
20 * `next build`, then a serve entry that `import("next")` +
21 * `next({ dev: false }).prepare()` + `getRequestHandler()` on `PORT`
22 * (default 3000). **Not** OpenNext — those wrappers are Lambda/workerd.
23 *
24 * The image `npm install`s `next`, `react`, and `react-dom`, and bakes
25 * `.next` plus `public/` into `/app`.
26 *
27 * During `alchemy dev` the site is Next's own dev server (`next dev`) and
28 * no cloud resources are declared; `Alchemy.remote()` opts back into the
29 * full live deployment.
30 *
31 * ### Creating Next.js Sites
32 * **Example:** Basic Next.js App
33 * ```typescript
34 * const site = yield* Railway.Website.Nextjs("Web", {
35 * rootDir: "./app",
36 * });
37 * ```
38 *
39 * ### Server Configuration
40 * **Example:** Process Environment
41 * ```typescript
42 * const site = yield* Railway.Website.Nextjs("Web", {
43 * rootDir: "./app",
44 * env: {
45 * API_BASE: "https://api.example.com",
46 * },
47 * });
48 * ```
49 *
50 * @resource
51 * @product Website
52 */
53export const Nextjs = (id: string, props: NextjsProps = {}) =>
54 makeFrameworkSite(id, props, {
55 name: "Nextjs",
56 framework: NEXTJS_FRAMEWORK_SPECIFIER,
57 target: NEXTJS_NODE_TARGET_SPECIFIER,
58 bake: "next",
59 install: ["next", "react", "react-dom"],
60 }).pipe(Namespace.push(id));