anomalyco/sst · error · VisibleError

SSR server bundle "index.mjs" not found in the build output

Error message

SSR server bundle "index.mjs" not found in the build output at:
  "${path.resolve(outputPath, ".output", "server")}".

If your SolidStart project is entirely pre-rendered, use the `sst.cloudflare.StaticSite` component instead of `sst.cloudflare.SolidStart`.

What it means

After a successful build with the correct preset, SST looks for the Nitro server bundle at `.output/server/index.mjs` and it is not there. This is the file SST wraps into the Cloudflare Worker for SSR.

Source

Thrown at platform/src/components/cloudflare/experimental/solid-start.ts:245

        await fs.readFile(
          path.join(outputPath, ".output", "nitro.json"),
          "utf-8",
        ),
      );

      if (!["cloudflare-module"].includes(nitro.preset)) {
        throw new VisibleError(
          `SolidStart's nitro.config.ts must be configured to use the "cloudflare-module" preset. It is currently set to "${nitro.preset}".`,
        );
      }

      // Make sure the server bundle is in the dist directory
      if (
        !(await existsAsync(
          path.join(outputPath, ".output", "server", "index.mjs"),
        ))
      ) {
        throw new VisibleError(
          `SSR server bundle "index.mjs" not found in the build output at:\n` +
            `  "${path.resolve(outputPath, ".output", "server")}".\n\n` +
            `If your SolidStart project is entirely pre-rendered, use the \`sst.cloudflare.StaticSite\` component instead of \`sst.cloudflare.SolidStart\`.`,
        );
      }

      // Ensure `.assetsignore` file exists and contains `server`
      const ignorePath = path.join(outputPath, ".output", ".assetsignore");
      const ignorePatterns = (await existsAsync(ignorePath))
        ? (await fs.readFile(ignorePath, "utf-8")).split("\n")
        : [];
      let dirty = false;
      ["server"].forEach((pattern) => {
        if (ignorePatterns.includes(pattern)) return;
        ignorePatterns.push(pattern);
        dirty = true;
      });

View on GitHub (pinned to a0bd20f762)

Solutions

  1. If the app is entirely pre-rendered, switch to `sst.cloudflare.StaticSite` instead of `sst.cloudflare.SolidStart`.
  2. Ensure at least one route uses SSR/on-demand rendering so Nitro emits `server/index.mjs`.
  3. Clean the `.output` directory and rebuild with the `cloudflare-module` preset.
  4. Verify `outputPath` in the component config points at the directory containing `.output`.

Example fix

// before (sst.config.ts)
const site = new sst.cloudflare.SolidStart(ctx, "Site", {});
// after (fully static site)
const site = new sst.cloudflare.StaticSite(ctx, "Site", { path: "my-solid-app" });
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync } from "fs";
if (!existsSync(".output/server/index.mjs")) console.warn("No SSR bundle — use StaticSite or enable SSR routes");

Type guard

const hasServerBundle = (out: string) => existsSync(`${out}/server/index.mjs`);

Try / catch

try {
  new sst.cloudflare.SolidStart(app, "Site", {});
} catch (e) {
  if (String(e).includes("index.mjs")) console.error("Switch to StaticSite or enable SSR");
  else throw e;
}

Prevention

When it happens

Trigger: buildPlan's existsAsync check on `<outputPath>/.output/server/index.mjs` fails — build produced only static output (fully pre-rendered routes), or the Nitro output layout changed / was customized, or the build wrote to a different directory.

Common situations: SolidStart app where every route is pre-rendered so no server bundle is emitted; customized Nitro `output` config; interrupted or partial build; SSR disabled in SolidStart config.

Related errors


AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30). Data as JSON: /api/errors/1526cf642f4505cb. Report an issue: GitHub.