npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ballatech/react-router7-preset-aws

v1.0.1

Published

Minimal AWS Lambda preset for React Router v7. Inspired by the Architect adapter, but without pulling in Architect or its unrelated dependencies that can clash when using AWS CDK with CloudFront, S3, and Lambda to deploy a website.

Downloads

60

Readme

@ballatech/react-router7-preset-aws

Minimal AWS Lambda preset for React Router v7. Inspired by the Architect adapter, but without pulling in Architect or its unrelated dependencies that can clash when using AWS CDK with CloudFront, S3, and Lambda to deploy a website.


Why?

  • Architect adapter inspiration: This preset mirrors the core request/response bridging needed to run React Router v7 on AWS Lambda (headers, cookies, binary body handling) and borrows the binary MIME list approach from Architect.
  • No unrelated deps: The Architect ecosystem can pull in extra dependencies. When pairing with AWS CDK + CloudFront + S3 + Lambda, those can cause version or bundling conflicts. This preset stays tiny and focused.

Features

  • React Router v7 on AWS Lambda (API Gateway v2)
  • Zero runtime dependencies beyond React Router node utilities
  • Binary response support (images, fonts, archives, etc.)
  • Set-Cookie passthrough compatible with API Gateway
  • Typed (TypeScript) API with a small surface area

Installation

pnpm add @ballatech/react-router7-preset-aws react-router @react-router/node
# or
npm i @ballatech/react-router7-preset-aws react-router @react-router/node
# or
yarn add @ballatech/react-router7-preset-aws react-router @react-router/node

Peer requirements:

  • react-router: ^7
  • @react-router/node: ^7

Usage

Create a Lambda handler that wires your React Router server build to API Gateway v2 events.

// server.ts
import { createRequestHandler } from '@ballatech/react-router7-preset-aws'
import type { ServerBuild } from 'react-router'

// Generated by `react-router build`
import * as build from './build/server'

export const handler = createRequestHandler({
  build: build as unknown as ServerBuild,
  // Optional: expose platform-specific values to loaders/actions
  // getLoadContext: async (event) => ({
  //   viewerCountry: event.headers['cloudfront-viewer-country'],
  // }),
})

Notes:

  • The handler expects API Gateway v2 events (HTTP API). It respects x-forwarded-host and host headers to construct the URL, which works behind CloudFront → API Gateway → Lambda.
  • Binary responses are automatically base64-encoded for content types in the common binary list.
  • Multiple Set-Cookie headers are moved to the API Gateway cookies array for proper delivery.

Build

Bundle the handler for Lambda after running the React Router build.

# Build the React Router app
react-router build

# Bundle the Lambda entry using esbuild (example)
node build.cjs

Example build.cjs used by the examples in this repo:

const esbuild = require('esbuild')

esbuild
  .build({
    entryPoints: ['server.ts'],
    bundle: true,
    platform: 'node',
    target: 'node22',
    external: ['node:stream'],
    outfile: 'build/lambda/index.cjs',
    sourcemap: true,
    format: 'cjs',
    metafile: true,
    legalComments: 'none',
  })
  .catch((error) => {
    console.error('Build failed:', error)
    throw error
  })

AWS CDK (example sketch)

This mirrors the working example in examples/my-react-router-app-infra. It hooks the Lambda to an HTTP API and fronts it with CloudFront. Static assets are served from S3 with optimized caching.

import * as path from 'node:path'
import { Stack, Duration } from 'aws-cdk-lib'
import * as lambda from 'aws-cdk-lib/aws-lambda'
import * as lambdaNodejs from 'aws-cdk-lib/aws-lambda-nodejs'
import * as apigwv2 from 'aws-cdk-lib/aws-apigatewayv2'
import * as integrations from 'aws-cdk-lib/aws-apigatewayv2-integrations'
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront'
import * as origins from 'aws-cdk-lib/aws-cloudfront-origins'
import * as s3 from 'aws-cdk-lib/aws-s3'
import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment'

export class WebStack extends Stack {
  constructor(scope: any, id: string) {
    super(scope, id)

    const bucket = new s3.Bucket(this, 'ClientBucket', {
      blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
    })

    const webFn = new lambdaNodejs.NodejsFunction(this, 'WebFn', {
      runtime: lambda.Runtime.NODEJS_22_X,
      memorySize: 1536,
      timeout: Duration.minutes(5),
      entry: path.resolve(__dirname, '../build/lambda/index.cjs'),
      bundling: {
        minify: true,
        target: 'node22',
        mainFields: ['module', 'main'],
        externalModules: ['aws-sdk', '@aws-sdk/*'],
      },
    })

    const api = new apigwv2.HttpApi(this, 'WebApi', {
      defaultIntegration: new integrations.HttpLambdaIntegration('WebIntegration', webFn),
    })

    const distribution = new cloudfront.Distribution(this, 'Distribution', {
      defaultBehavior: {
        origin: new origins.HttpOrigin(
          `${api.httpApiId}.execute-api.${Stack.of(this).region}.${Stack.of(this).urlSuffix}`,
        ),
        allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL,
        cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED,
        viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
      },
      additionalBehaviors: {
        'assets/*': {
          origin: new origins.S3Origin(bucket),
          allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD,
          cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
          viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
        },
      },
    })

    new s3deploy.BucketDeployment(this, 'DeployClient', {
      destinationBucket: bucket,
      sources: [s3deploy.Source.asset(path.resolve(__dirname, '../build/client'))],
      distribution,
    })
  }
}

CloudFront + S3 notes:

  • Static assets: upload your app's static assets to S3 and front them with CloudFront.
  • Dynamic requests: add a behavior in CloudFront that forwards SSR/app routes to the API Gateway origin. Ensure headers/cookies (Host, X-Forwarded-Host, etc.) are forwarded as needed by your setup.

API

type GetLoadContextFunction = (event: APIGatewayProxyEventV2) => AppLoadContext | Promise<AppLoadContext>

createRequestHandler({
  build: ServerBuild,
  getLoadContext?: GetLoadContextFunction,
  mode?: string, // defaults to process.env.NODE_ENV
}): APIGatewayProxyHandlerV2

License

MIT © Ballatech