Skip to content

Conversation

moonclavedev
Copy link
Contributor

@moonclavedev moonclavedev commented Sep 9, 2025

Changes

  • Adds collapseHeaders option to experimental.csp configuration
  • When used with adapters supporting experimentalStaticHeaders, consolidates all CSP headers into a single catch-all route
  • Prevents build errors for large sites with many routes / large CSP config
  • Reduces configuration file size from MB to KB for large sites (especially with i18n)
  • Maintains full backward compatibility with existing CSP usage
  • Benefits all adapters that support experimentalStaticHeaders automatically (Vercel, Netlify, Node)

Before: 15k+ individual CSP route entries → 9MB config file → Build failures
After: 1 global CSP route entry → 10KB config file → Successful builds

Reference: #13996 (comment)

Usage:

// Default behavior (unchanged)
experimental: {
  csp: true
}

// New option
experimental: {
  csp: {
    collapseHeaders: true
  }
}

Testing

  • Added tests for all (3) adapters that support experimentalStaticHeaders using existing static-headers.test.js files for Vercel, Netlify, and Node adapters.
  • Created test fixtures with collapseHeaders: true configuration for each adapter
  • Verified collapsed headers create single catch-all route entries across all platforms
  • Confirmed backward compatibility with existing CSP configurations
  • All tests passing

Docs

This is a core CSP feature that works universally with all adapters supporting experimentalStaticHeaders which affects behavior for large sites experiencing build size limits with CSP enabled.

Documentation updates needed for:

  • New collapseHeaders option in experimental CSP configuration
  • When to use collapsed vs per-route CSP headers
  • Usage examples with different adapters
  • Build / performance implications and best practices

/cc @withastro/maintainers-docs for feedback!

Adds `collapseHeaders` option to `experimental.csp` that, when used with experimentalStaticHeaders, consolidates all CSP headers into a single catch-all route, preventing build errors and improving performance for large sites with many routes.

- Add collapseHeaders boolean option to experimental.csp configuration
- Modify RouteToHeaders population in generate.ts to support header collapsing
- Add tests for Vercel, Netlify, and Node adapters
- Maintain backward compatibility with existing CSP usage

Benefits all adapters that support experimentalStaticHeaders automatically.
Reduces config file size from MB to KB for large sites.
Copy link

changeset-bot bot commented Sep 9, 2025

🦋 Changeset detected

Latest commit: 19f5098

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added pkg: integration Related to any renderer integration (scope) pkg: astro Related to the core `astro` package (scope) docs pr semver: minor Change triggers a `minor` release labels Sep 9, 2025
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is blocked because it contains a minor changeset. A reviewer will merge this at the next release if approved.

Copy link

codspeed-hq bot commented Sep 9, 2025

CodSpeed Performance Report

Merging #14339 will not alter performance

Comparing moonclavedev:feat/experimental-csp-collapse-headers (19f5098) with main (17c7b03)1

Summary

✅ 6 untouched benchmarks

Footnotes

  1. No successful run was found on main (468c845) during the generation of this report, so 17c7b03 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@ascorbic
Copy link
Contributor

I'll defer to @ematipico on this as he's leading the feature dev, but I'm in two minds about this. On the one hand I can see the value in something like this, but on the other I'm not sure a catch-all route is the right approach. It's a bit of a blunt instrument and doesn't allow for different directives on different paths. If we do land this, I think it should be called something like useCatchAllRoute.

@ematipico
Copy link
Member

ematipico commented Sep 12, 2025

I also share the same concerns as @ascorbic

The 'catch-all' route isn't actually the solution. It could be helpful in most cases, but there may be instances where this approach could lead to issues. For example, the current implementation is a bit naive and it doesn't take into consideration the fact that different pages could emit different headers.

We have functions such as Astro.csp.insertScriptHash, which inserts a new hash in the current page being rendered. Or there might be two pages that emit different CSS styles.

Maybe the "catch-all" should work in a way that we catch all routes that have the same headers, and we create the ""catch-all"" for all those routes. It isn't real catch-all, it's a glob that catches all routes that have the same headers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs pr pkg: astro Related to the core `astro` package (scope) pkg: integration Related to any renderer integration (scope) semver: minor Change triggers a `minor` release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants