Skip to main content

CSP (Cacheable Server Props) Page

This works like SSR (server-rendered) page, however, the ctx we pass back to you only contains static data, so the page can be cached.

The cacheableServerProps helper

Export getServerSideProps with the cacheableServerProps helper.

Note that because the ctx we provide to you only contains static data, you will implement your data-fetching logic inside the getStaticProps function.

import { cacheableServerProps, callAPI } from '@traveloka/core';

export default MyPage() {
return <>Hello</>
}

export const getServerSideProps = cacheableServerProps({
resources: [MyComponentRQ, MyOtherComponentRQ],
getStaticProps: async (ctx, rawAppContext) => {
const res = await callAPI(ctx, options);
return {
props: {
myData: res.result.data,
},
// Default is 10m (600s)
revalidate: 10 * 60,
};
},
});

Dynamic Path Configuration

For Next.js routes with dynamic segments (e.g., [token], [id]), you need to configure webcfn to enable caching.

Configuration File

Add path patterns to packages/proxies/webcfn/lambda/config.json:

[
{
"pattern": "/booking/v2/[token]"
},
/**
* Prevent '/activities/country/product/xxx' being replaced
*/
{
"pattern": "/activities/country/product/[nameId]",
"rewrite_uri": false
},
{
"pattern": "/activities/[country]/[type]/[nameId]"
}
]

Supported Pattern Formats

  • [param] - Single dynamic segment (e.g., [token], [id])
  • Multiple dynamic segments in one path are supported
  • [...param] (catch-all) is NOT supported for caching

How It Works

When a request matches a configured pattern:

  1. Path Rewrite: Dynamic segments are replaced with parameter names

    • /booking/v2/abc123/booking/v2/token
  2. Headers Added:

    • X-Custom-Origin-Uri: Original path for downstream routing
  3. Query Parameter: __cfnrewrite__=1 is appended to mark the rewrite

  4. Client-Side: The browser URL remains unchanged; useNextRouter and useCurrentRoute handle the mapping

Configuration Options

OptionTypeDefaultDescription
patternstringrequiredPath pattern with dynamic segments in brackets
rewrite_uribooleantrueSet to false to disable rewriting for this pattern

Important Notes

  • Patterns must start with /
  • Locale prefix (e.g., /id-id, /en-sg) is automatically handled
  • The rewrite happens at the CloudFront edge (webcfn Lambda)
  • Original dynamic values are preserved in X-Custom-Origin-Uri header for routing decisions

Developer Testing & Release Guide

1. Local Configuration

Configure the dynamic path pattern in @packages/proxies/webcfn/lambda/config.json:

[
{
"pattern": "/booking/v2/[token]"
}
]

2. Local Development Testing

After configuring the file, the Next.js Service will receive the static path (e.g., /booking/v2/token). The original path is preserved in the Request Header X-Custom-Origin-Uri.

Verify Path Rewrite Success:

Open browser console and check __NEXT_DATA__.query:

__NEXT_DATA__.query;
// Expected output if rewrite is successful:
// { token: "token" } // Static value, not the dynamic value like "abc123"

If the rewrite is successful, dynamic parameters will show static values (parameter names) instead of actual dynamic values.

Ensure the page behaves correctly in local environment.

3. PR Environment Testing

Verify Path Rewrite in PR:

Similarly, open browser console in the PR environment and check:

__NEXT_DATA__.query;
// Should show static parameter names, not dynamic values

Confirm dynamic parameters have been replaced with static values and the page functions correctly.

4. Staging Environment Deployment

After confirming the page works correctly in PR:

  1. Contact the Infra team to deploy the page to the staging environment
  2. Configure the staging CDN with the webcfn Lambda
  3. Verify CDN Caching is active - check response headers for cache hits
  4. Test that the page behaves correctly in the staging environment

5. Production Release

Once staging testing is complete:

  1. Merge the code and release a new version

  2. ⚠️ CRITICAL: Deployment Order

    You MUST deploy in this order:

    First: Deploy www Next.js server

    Then: Contact Infra team to deploy CloudFront CDN changes to production

    Why this order matters:

    • The www Next.js server can work without the CDN path rewrite Lambda
    • However, if you deploy the CDN Lambda first but your www page isn't adapted for static paths, it will cause errors
    • The www server handles both dynamic and static paths gracefully

6. Post-Production Verification

After CDN deployment:

  1. Verify pages are being served from CDN cache
  2. Check __NEXT_DATA__.query in production to confirm static values
  3. Monitor for any errors or unexpected behavior
  4. Ensure all dynamic paths are working correctly

Summary of Key Points:

  • ✅ Configure config.json for dynamic paths
  • ✅ Verify using __NEXT_DATA__.query (should show static values)
  • ✅ Test in local → PR → Staging → Production
  • Critical: Deploy www server BEFORE CDN changes
  • ✅ Contact Infra team for staging and production CDN configuration

Query String Stripping

For CSP pages, you can strip non-cacheable query params before the request reaches Next.js. This helps prevent sensitive or non-deterministic query values from being embedded in SSR HTML (for example inside __NEXT_DATA__.query), while keeping the browser URL unchanged.

How to Configure

  1. Add your cache key type in packages/core/next/view-cache-key/types.ts:
export type FlightCSPCacheKey = 'ap' | 'utm_source' | 'findcheapestdate';
export type CSPCacheKey = PaymentCSPCacheKey | FlightCSPCacheKey;
  1. Add route-level preserved query keys in packages/core/next/view-cache-key/queryCacheKeySetting.ts:
export const FlightQueryCacheKeySetting: {
[pathname: string]: Array<FlightCSPCacheKey>;
} = {
'/flight/fullsearch': ['ap', 'findcheapestdate', 'utm_source'],
};

export const queryCacheKeySetting: {
[pathname: string]: Array<CSPCacheKey>;
} = {
...FlightQueryCacheKeySetting,
...PaymentQueryCacheKeySetting,
};
  1. Export your setting from packages/core/next/view-cache-key/index.ts.

  2. Wire middleware in the app server:

import { queryStripMiddleware } from '@traveloka/core/server';
import { FlightQueryCacheKeySetting } from '@traveloka/core/next/view-cache-key';

server.use(queryStripMiddleware(FlightQueryCacheKeySetting));

Example

Input URL:

https://www.traveloka.com/en-id/flight/fullsearch?ap=CGK.AMS&dt=28-11-2025.NA&ps=1.0.0&sc=ECONOMY

Config:

{
'/flight/fullsearch': ['ap', 'utm_source', 'findcheapestdate']
}

URL received by Next.js server:

https://www.traveloka.com/en-id/flight/fullsearch?ap=CGK.AMS&__cfnrewrite__=1

In this example, only configured cache keys (plus default preserved keys) remain.

Default Preserved Keys and Behavior

  • Always preserved: cur, currency, __nextDataReq
  • __cfnrewrite__=1 is appended when stripping happens
  • Browser URL does not change; stripping only affects server-side request handling
  • Client hooks (useNextRouter, useCurrentRoute) restore stripped query params from the real browser URL

Hydration Note

When stripped params affect render output, use hydrationSafe: true in useNextRouter / useCurrentRoute to avoid hydration mismatch. Use default behavior (hydrationSafe: false) when those params do not affect SSR HTML output.