Greenwood v0.32.0

Published: April 12th, 2025

AWS logo

What's New

Along with a round of enhancements and bug fixes, this new Greenwood release brings with it two big new features we are excited to share. We now have an official AWS Adapter for deploying dynamic SSR pages and API routes to Lambda functions, as well as now making our TypeScript plugin officially built-in; no more plugin needed anymore to use TypeScript with Greenwood! There was also a small minimum version bump for NodeJS.

This release was also the by-product of some great feedback, support, and contributions from our community. In particular the built-in TypeScript support was very much a collaborative process that really helped to strengthen Greenwood as a project that can be open to feedback and help it continue to grow as a productive experience to develop with. We very much enjoyed the conversations we had around this topic and the end result we produced. Thank you so much to everyone who got involved with us for this release, it means a lot to us and it's great to see what you're all building with Greenwood! 💚

Please refer to the release notes for the complete changelog and overview of breaking changes.

AWS Adapter

While static hosting of your Greenwood project was always possible with AWS, serverless support on Lambda for SSR pages and API routes didn't have a formal solution... until now! With this release, there is now an official adapter plugin for generating Lambda compatible function code for your dynamic pages and routes. ☁️

import { greenwoodPluginAdapterAws } from "@greenwood/plugin-adapter-aws";

export default {
  plugins: [greenwoodPluginAdapterAws()],
};

Taking into consideration that there are many methods and options for deploying to AWS, this adapter plugin is primarily focused on generating consistent and predictable build output that can be complimented by some form of IaC (Infrastructure as Code) or deployment tooling of your choice. The build output will look similar to Greenwood's own standard build output and will be available in the .aws-output/ folder at the root of your project after running the build command.

.aws-output/
  api/
    event/
      event.js
      index.js
      package.json
    search/
      ...
  routes/
    admin/
      ...
    products/
      index.js
      package.json
      products.route.chunk.jgsTuvlz.js
      products.route.js

For each of the folders in the api/ or routes/ directories, it would just be a matter of creating a zip file for each folder / route and uploading those, or ideally pointing your IaC tooling to those output folders. For example, here is a simplified example from our SST example:

// 1) Configure an API Gateway for routing SSR pages and API routes
const api = new sst.aws.ApiGatewayV2("MyApi");

// products page
api.route(`GET /routes/products`, {
  bundle: `.aws-output/routes/products`,
  handler: "index.handler",
});

// search API
api.route(`GET /api/search`, {
  bundle: `.aws-output/api/search`,
  handler: "index.handler",
})

// 2) Setup hosting for static content
const frontend = new sst.aws.StaticSite("MyStaticSite", {
  path: "./",
  build: {
    output: "public"
  },
})

// 3) Configure a CloudFront distribution with behaviors for SSR pages, API routes, and static content
const router = new sst.aws.Router("MyRouter", {
  routes: {
    "/api/*": api.url,
    {
      url: api.url,
      rewrite: {
        regex: `^/products/$`,
        to: `/routes/products`
      }
    },
    "/*": frontend.url
  },
  invalidation: true,
});

// 4) Configure the SST app
export default $config({
  app(input) {
    return {
      name: "my-app",
      removal: input?.stage === "production" ? "retain" : "remove",
      protect: ["production"].includes(input?.stage),
      home: "aws",
    };
  },
  async run() {
    router
  },
});

Naturally you wouldn't want to hardcode these, so please check out our full AWS hosting documentation for more details, including example repositories using SST and Architect.

Built-in TypeScript Support

With this release, Greenwood now provides built-in support for TypeScript, with the ability to fallback to using tsc if certain TypeScript features you're using (like Decorators, enums, namespaces, etc) are not supported through just type stripping alone. This was motivated due to NodeJS version >= 22.6.0 now making type stripping available through the --experimental-strip-types flag. This also means you can remove Greenwood's TypeScript plugin as it is has been deprecated with this release.

{
  "scripts": {
    "build": "NODE_OPTIONS='--experimental-strip-types' greenwood build"
  }
}

If you were using our TypeScript plugin, you should remove that from your Greenwood configuration file as it has now been deprecated.

This also means that you can author your Greenwood configuration files and plugins with TypeScript!

// greenwood.config.ts
import type { Config } from "@greenwood/cli";

const config: Config = {
  // ...
};

export default config;

For actual type-checking, you can of course install typescript in your project and use Greenwood's minimum recommended tsconfig.json settings so that you can run tsc during CI.

{
  "compilerOptions": {
    "module": "preserve",
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "verbatimModuleSyntax": false,
    "noEmit": true,
    "erasableSyntaxOnly": true
  }
}

Check out our TypeScript docs to learn more about getting setup with TypeScript and Greenwood.


As always, we're excited to see where the community can take Greenwood and are always available to chat on GitHub or Discord. See you for the next release! ✌️