Stack guide
Next.js and Stripe Connect: refunds across server actions and routes
Next.js App Router gives you three places refunds might live — server actions, route handlers, legacy API routes — and only opinions about which is right. Money paths change the calculus: server actions are public endpoints needing re-authentication from scratch, Edge runtime cannot touch secret-dependent crypto, and one misnamed environment variable drops both Connect flags without any error ever appearing.
Route handlers vs server actions for money
Server actions re-authenticate from scratch on every invocation — treat arguments as hostile, verify session and ownership before any Stripe call. Route handlers suit webhook receivers (signature verification lives naturally there). Mixing concerns across both is fine; trusting either implicitly is not.
The Edge/Node split
Signature verification runs happily on Edge; anything requiring node:crypto-backed secret material does not. Production architecture mirrors this: Edge receiver verifies and enqueues, Node workers do detection and recovery work. Local dev hides the boundary until deploy surprises you.
The silent env-var trap
Flags sourced from configuration (process.env.REVERSE_TRANSFERS === "true") fail closed when staging variables misspell names — refunds succeed, transfers strand, nothing logs. Hard-code true flags; reserve configuration for genuinely variable policy like floors.
// Fragile: config-gated correctness
const flags = process.env.CONNECT_REVERSALS ? {...} : {};
// Robust: correctness isn't configurable
await stripe.refunds.create({ charge, reverse_transfer: true, refund_application_fee: true });RSC caching showing stale amounts
Cached components rendering amount_refunded predate reversals landing elsewhere. Route from cached views; decide from fresh fetches at action time — the payload-staleness lesson wearing frontend clothing.
Common questions
Can refunds run entirely on Edge runtime?
Signature verification yes; anything touching secret-derived crypto needs Node runtime. Plan the split deliberately rather than discovering it in production logs.
Does this require a FeeGuard integration?
No — the page stands alone as stack guidance. FeeGuard observes your event stream externally rather than embedding in it.