Apps

Supported Frameworks

Learn about Supported Frameworks in WaymakerOS.

FrameworksRuntimes

Host detects your framework automatically on every push and deploys it the right way — static sites to Waymaker's global edge network, server apps to the server runtime. You don't configure the pipeline; you push code.

The matrix

FrameworkStaticServer (SSR / API routes)Notes
Next.js✅ (output: "export")Fully supportedApp Router, Server Components, Route Handlers, API routes, streaming — all work. No special config.
Custom TypeScript server (Hono, itty-router, plain fetch handler)Supported (manifest)Declare it in waymaker.config.ts — see below.
Vite / React / Vue / SolidStatic builds deploy automatically.
SvelteKit✅ (adapter-static)🔜 PlannedServer builds currently deploy their static output.
Nuxt 3✅ (static preset)🔜 PlannedAs above.
Remix✅ (static export)🔜 PlannedAs above.
Astro🔜 PlannedServer-adapter apps detected; static output deploys today.
Gatsby / Docusaurus / EleventyStatic generators deploy automatically.

How detection works

  1. Your manifest wins. If waymaker.config.ts declares type and runtime, Host obeys it — no guessing.
  2. Signals as fallback. No manifest? Host reads your package.json and framework config (for example, next.config.* with output: "export" means static; without it, server).
  3. Re-checked on every push. Change your app from static to server and the next deploy reclassifies it automatically — the Runtime chip in Host shows what detection concluded.

Custom TypeScript servers

Building an API or server app without a big framework? Declare it:

// waymaker.config.ts
export default {
  type: 'app',
  runtime: 'server',
  entry: 'src/server.ts',   // optional — defaults to src/index.ts
}

Your entry file exports a standard fetch handler (Hono apps do this natively):

import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.text('Hello from Waymaker'))
export default app

Host bundles it and deploys it to the server runtime. This lane is manifest-only by design — Host never guesses that an app is a custom server.

Databases

Any app can have its own Postgres database (one per app): provision it from the Databases module in Host or with waymaker host db create <app>, pick a region (Sydney, Singapore, Frankfurt, London, N. Virginia — permanent for the life of the database), and your app reads DATABASE_URL from its environment — the same variable Prisma, Drizzle and every standard scaffold already expect, so a stock project connects without changes. Schema changes ship as migrations: waymaker host db migrate <app>.

Output folders — one setting worth getting right

output_dir means "publish this folder as-is". Leave it empty for a server app — Host builds and deploys the server for you.

Never set it to .next. That is Next.js's internal build folder, not a website. Setting it publishes scaffolding: the deploy succeeds, the app shows as active, and every page returns 404. Host now refuses the value, but the reasoning is worth carrying — if your framework builds a server, there is no folder to publish.

Static exports do have one: Next.js with output: "export" produces out.

Troubleshooting

  • Every page 404s but the deploy succeeded — the app published a build folder instead of a site. Clear output_dir and set the runtime to server, then redeploy. Run waymaker host doctor <app> to confirm what Host thinks your app is.
  • "Build output directory does not exist" — your build command didn't produce the configured output directory, or the app is actually a server app: declare runtime: "server" in the manifest.
  • Pages render but the data is empty — the app is being served as a static site, so nothing runs per request. waymaker host doctor <app> shows the runtime it actually deployed as, next to the one you declared.
  • Server frameworks marked 🔜 currently deploy their static output, with a warning in the build log naming what will not run. Full server support lands per framework — declare intent in the manifest and the build log tells you exactly what happened.

Talking to your database from a server app

Two things are not guessable, and each costs a day if you get it wrong.

Use @waymakeros/db, not pg. pg (node-postgres) opens a raw TCP socket, which the server runtime cannot do. It fails at build time with Could not resolve "pg-cloudflare" — a package you have never heard of, named hundreds of lines into a log.

npm install @waymakeros/db
import { sql } from '@waymakeros/db'
const rows = await sql`select * from centres where id = ${id}`

It reads DATABASE_URL for you, so there is nothing to wire up.

Do not hold a connection or pool across requests. Create it inside the request that uses it. A pool cached at module scope — exactly how you would write it on Node — makes requests hang non-deterministically once deployed: one page returns 200, the next 500, the next 200, on the same code and the same deploy. It reads as a bug in the failing page, and it is not.

If you genuinely need an interactive transaction, open a pool inside that one function and close it before returning.

Signing your own users in

Apps with a database can have their own sign-in — your customers, members or staff, with accounts that live in your app's database rather than in Waymaker.

waymaker host db auth provision <app>
waymaker host db auth deploy <app>

Email and password works out of the box, and so does password reset. Where the account is a shared mailbox rather than one person — a site address, a team inbox — you can offer one-time codes by email instead, so nobody has to share a password:

waymaker host db auth methods <app> --otp on
waymaker host db auth deploy <app>

Two-factor sign-in is available too, and can be required for particular roles while leaving others alone. See the developer documentation for the sign-in endpoints your app calls.