Context
We are using flags/next with @flags-sdk/posthog in a Next.js app deployed on Vercel.
Installed versions in the app where we reproduced this:
@flags-sdk/posthog@0.2.2
flags@4.0.6
posthog-js@1.377.0
@flags-sdk/posthog depends on posthog-node@4.11.1
We also have POSTHOG_PERSONAL_API_KEY configured because the Flags Explorer / provider-data endpoint needs it to discover PostHog feature flag definitions.
Problem
The default postHogAdapter passes POSTHOG_PERSONAL_API_KEY into the runtime posthog-node client and sets featureFlagsPollingInterval: 10000.
In posthog-node, providing a personal API key enables local evaluation. That creates a feature-flag poller which starts loading local-evaluation data and then repeats every polling interval.
On Vercel/serverless-style deployments this means each warm server process can have its own poller. With a 10s interval, one warm process can make about 8,640 feature-flag polling requests per day. A few dozen warm processes can therefore generate hundreds of thousands of PostHog feature flag requests/day, even for an app with very few real users.
This is what we observed: normal days were around 0-5k feature flag requests, while after adopting the PostHog Flags SDK adapter we started seeing spikes around 100k-350k/day. Those numbers are consistent with a per-process 10s poller, not with our actual user traffic or explicit flag evaluations.
Why this is surprising
POSTHOG_PERSONAL_API_KEY is needed for provider data / Flags Explorer discovery, but its presence also changes runtime evaluation behavior by enabling local-evaluation polling inside the default adapter.
Those are separate concerns:
- provider data discovery needs the personal API key
- runtime flag evaluation in a serverless app may not want local-evaluation polling
Right now the default adapter couples them. If the env var exists, the runtime client gets it and polling starts.
Workaround we applied
We stopped using the default postHogAdapter singleton and created the adapter explicitly without personalApiKey:
const postHogAdapter = createPostHogAdapter({
postHogKey: process.env.NEXT_PUBLIC_POSTHOG_KEY!,
postHogOptions: {
host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
disableGeoip: true,
},
})
We kept provider-data discovery separate:
getProviderData({
personalApiKey: process.env.POSTHOG_PERSONAL_API_KEY,
projectId: process.env.POSTHOG_PROJECT_ID,
})
We also disabled browser-side PostHog feature flags because this app only evaluates flags server-side:
posthog.init(key, {
advanced_disable_feature_flags: true,
})
Proposed solution
Please consider one of these changes for @flags-sdk/posthog:
- Do not pass
POSTHOG_PERSONAL_API_KEY to the runtime posthog-node client by default in serverless usage.
- Add an explicit adapter option/env var to enable local evaluation, so polling only starts when the user opts in.
- Add an explicit adapter option/env var to disable local evaluation while still allowing
getProviderData / Flags Explorer to use POSTHOG_PERSONAL_API_KEY.
- At minimum, document that the default PostHog adapter starts a 10s per-process local-evaluation poller when
POSTHOG_PERSONAL_API_KEY is present, and that this can materially increase PostHog feature flag request billing on Vercel.
Expected behavior
Configuring POSTHOG_PERSONAL_API_KEY for provider-data discovery should not implicitly start runtime feature-flag polling in every warm server process.
Actual behavior
The default adapter passes the personal API key into posthog-node; posthog-node enables local evaluation and polls feature flag data every 10s per process.
Context
We are using
flags/nextwith@flags-sdk/posthogin a Next.js app deployed on Vercel.Installed versions in the app where we reproduced this:
@flags-sdk/posthog@0.2.2flags@4.0.6posthog-js@1.377.0@flags-sdk/posthogdepends onposthog-node@4.11.1We also have
POSTHOG_PERSONAL_API_KEYconfigured because the Flags Explorer / provider-data endpoint needs it to discover PostHog feature flag definitions.Problem
The default
postHogAdapterpassesPOSTHOG_PERSONAL_API_KEYinto the runtimeposthog-nodeclient and setsfeatureFlagsPollingInterval: 10000.In
posthog-node, providing a personal API key enables local evaluation. That creates a feature-flag poller which starts loading local-evaluation data and then repeats every polling interval.On Vercel/serverless-style deployments this means each warm server process can have its own poller. With a 10s interval, one warm process can make about 8,640 feature-flag polling requests per day. A few dozen warm processes can therefore generate hundreds of thousands of PostHog feature flag requests/day, even for an app with very few real users.
This is what we observed: normal days were around 0-5k feature flag requests, while after adopting the PostHog Flags SDK adapter we started seeing spikes around 100k-350k/day. Those numbers are consistent with a per-process 10s poller, not with our actual user traffic or explicit flag evaluations.
Why this is surprising
POSTHOG_PERSONAL_API_KEYis needed for provider data / Flags Explorer discovery, but its presence also changes runtime evaluation behavior by enabling local-evaluation polling inside the default adapter.Those are separate concerns:
Right now the default adapter couples them. If the env var exists, the runtime client gets it and polling starts.
Workaround we applied
We stopped using the default
postHogAdaptersingleton and created the adapter explicitly withoutpersonalApiKey:We kept provider-data discovery separate:
We also disabled browser-side PostHog feature flags because this app only evaluates flags server-side:
Proposed solution
Please consider one of these changes for
@flags-sdk/posthog:POSTHOG_PERSONAL_API_KEYto the runtimeposthog-nodeclient by default in serverless usage.getProviderData/ Flags Explorer to usePOSTHOG_PERSONAL_API_KEY.POSTHOG_PERSONAL_API_KEYis present, and that this can materially increase PostHog feature flag request billing on Vercel.Expected behavior
Configuring
POSTHOG_PERSONAL_API_KEYfor provider-data discovery should not implicitly start runtime feature-flag polling in every warm server process.Actual behavior
The default adapter passes the personal API key into
posthog-node;posthog-nodeenables local evaluation and polls feature flag data every 10s per process.