Skip to main content
Leaving The Matrix
nova-dev 7 min read

Twelve Amplify failures, then five minutes on Vercel

The members portal at nova.leavingthematrix.io is live, in sandbox mode. Two hours of deploy debugging, twelve consecutive Amplify failures, then a host swap that worked first try.

#nova#war-story#architecture

Nova's members portal is live at nova.leavingthematrix.io. Sandbox mode for now — Stripe test keys, the LTM /membership page is recruiting beta testers with a "Help Me Test For Free!" button and the 4242 4242 4242 4242 card details inline. Public launch is one Stripe live-keys swap away.

The interesting story isn't the launch itself. It's the four hours between "deploy to Amplify" and "live on Vercel," and what that taught me about picking the right host for the right shape of app.

The plan was Amplify

Vasilion's GitHub org already has Amplify set up. The LTM site lives there. Trajectory lives there. Unycross lives there. The natural answer for the new Next.js app at apps/web was "just put it on Amplify too." Same workflow, same console, same DNS pattern.

First deploy attempt: failed. Second: failed. The error was the same on both: Amplify's SSR validator rejecting the artifact with "Server trace files are not found."

Twelve consecutive failures

Over the next two hours I tried every reasonable combination I could find:

  • Vanilla pnpm install in the build phase.
  • Next.js output: "standalone".
  • Hoisted node-linker = "hoisted" in .npmrc.
  • pnpm deploy --legacy to flatten dependencies.
  • Custom amplify.yml restructuring — rebuilding the artifact in a deploy directory with manually placed server.js, required-server-files.json, and a real flat node_modules.
  • Build-inside-deploy-dir patterns where the cd happened before the build, after the build, and around the validator.

Same error every time. The artifact had textbook structure on multiple attempts — 60+ MB of real flat node_modules, .next/server/app/* with every manifest the docs called out, server.js at the root, required-server-files.json hoisted properly. The Amplify SSR validator was rejecting it with the same string each time, and the string didn't change between attempts that produced structurally different artifacts.

That last detail was the actual diagnosis. When four meaningfully different artifact shapes produce the same error, the error isn't telling you what's wrong. It's telling you the validator can't recognize what it's looking at.

The pivot

Dropped Amplify. Connected the same repo to Vercel.

Five minutes later it was live. No amplify.yml, no standalone-output dance, no node-linker tweaks, no manual artifact restructuring. The same code that Amplify had rejected twelve times deployed cleanly on first try. nova.leavingthematrix.io wired in via Route 53 CNAME, SSL auto-provisioned, working portal.

Vercel's pricing: Hobby covers all the technical limits for an app this size. Going to flip to Pro ($20/mo) before public launch since Hobby ToS technically requires non-commercial use, but for sandbox testing the free tier is fine.

Why this happened

I want to be careful not to dunk on Amplify here. Amplify is genuinely excellent for static sites and standard Node apps — the LTM site lives there happily, Trajectory lives there happily, the unycross blog you're reading on the unycross side lives there happily. The shape of app that made it fall down is specific:

pnpm monorepo + Next.js 15.5 + SSR + standalone output

That combination has a lot of moving parts. The pnpm side wants a workspace-aware install with hoisted dependencies. The Next.js standalone-output side wants its build artifact restructured into a specific shape. Amplify's SSR validator is conservative about what it accepts. The intersection of those three constraints didn't converge for us in any of the twelve attempts.

Vercel built that exact intersection as a first-class workflow because Next.js is their product. They've solved the workspace-detection, the standalone-output handling, and the SSR-edge integration in code that's been hardened by every Next.js app on the platform. Picking Vercel for a Next.js SSR app is not "Vercel is better" — it's "right tool for the right job." Picking Amplify for a static Astro site (which is what LTM is) was the right call for the same reason. Different tools, different shapes.

The lesson, banked: when an error message stops changing across structurally-different attempts, stop tweaking and consider whether the tool is wrong for the workflow. Sometimes the answer is "this stack doesn't support that natively." Two hours of amplify.yml iteration would have been better spent on the host swap that took five minutes.

Two collateral changes

While the deploy was unblocking, two other things shifted shape:

FRED dropped from the web /macro page. Vercel's iad1 region apparently has unreliable connectivity to FRED's CSV endpoint. CSV fetches timed out, cache got poisoned with empty results, aggressive AbortSignal handling didn't fix it. Spent about thirty minutes on timeout bumps and throw-on-empty handling before deciding that if FRED can't render reliably from the web, it shouldn't render at all there. Removed all FRED-dependent sections (rates / yield curve / growth + inflation / labor) from the web /macro page. 439 lines deleted. The page is now Polymarket + Volatility Dashboard only.

Nova desktop still has FRED via its own cache — this isn't a Nova-wide regression, just a web-side one. Future option if web ever needs FRED back: mirror FRED snapshots into Neon (same pattern we already use for ClickCapital data), have Nova desktop push, web reads from DB. About thirty minutes of refactor when needed. Not blocking launch.

Forced Stripe checkout flow. Luke's wife test-signed-up the new portal and got into the members area immediately — full access, no payment, no tier check. The Clerk sign-up flow was redirecting straight to /macro rather than gating on payment. Real launch-blocker.

New /checkout page (server component) checks the user's tier on every visit. Pro and Elite users redirect straight to /macro. Free users land on a client component that fires POST /api/checkout on mount and follows the returned Stripe URL via window.location. Clerk's SignIn and SignUp forceRedirectUrl changed from /macro to /checkout; the page self-routes pro users so it works for both new sign-ups and returning sign-ins. Tested end-to-end with the test card — webhook fires, users.tier flips to pro in Neon, user lands at /macro?checkout=success.

Where this leaves Nova

Members portal live in sandbox mode at nova.leavingthematrix.io. Anyone who hits LTM /membership can click "Help Me Test For Free!" → sign up via Clerk → get redirected to Stripe with the test card details visible on the previous page → land in the members area as a Pro tier. Mobile UX got a parallel overhaul this session (a different post; the short version is hamburger menu, hand-rolled click-toggle popover with viewport clamping for the info bubbles, wrapping-chip sub-tabs, and the h-screenh-dvh trick for mobile Chrome's URL-bar handling).

Last technical step before public launch is the Stripe live-keys swap. About ten minutes of work: create live Product + Price in the Stripe dashboard, swap five env vars in the Vercel project (sk_test_*sk_live_*, pk_test_*pk_live_*, the live price IDs and webhook secret), revert the LTM sandbox banner, push.

Nova Fund inception is still Sunday, May 10. Four days out. Sunday morning, the simulator runs its first weekly_run, proposes its first trades against universal Nova Score, the click-to-approve UI surfaces them, the memo gets voiced and published. Public track record starts from zero. The diagnostic log from last post will be watching.

Free Your Mind · Free weekly newsletter

Liked this? Get the next one in your inbox.

One full ticker through the framework + the lesson behind it, every week. Unsubscribe in one click.

Want the full picture?

Smart-money flow, real conversations, the whole framework.

Leave the Matrix
Leave the Matrix