posthog-js icon indicating copy to clipboard operation
posthog-js copied to clipboard

PostHog Next.js causing memory leaks

Open mohamedgad21 opened this issue 1 year ago • 3 comments

Hi, I have been using PostHog for a while and just discovered it is causing a serious memory leak. I am using [email protected].

I solved the leak by lazily importing Posthog.

export const CSPostHogProvider = (props: IProps) => {
  const [client, setClient] = useState<PostHog | undefined>();

  useEffect(() => {
    const handler = async () => {
      const posthog = (await import("posthog-js")).posthog;

      const client = posthog.init(
        process.env["NEXT_PUBLIC_POSTHOG_KEY"] ?? "",
        {
          api_host: `${FRONT_END_URL}/ingest`,
          capture_pageview: false,
        },
      );
      setClient(client);
    };

    handler();
  }, []);

  if (!client) return props.children;
  return <PostHogProvider client={client}>{props.children}</PostHogProvider>;
};

The above code solved the leak on the server side, but the thing is I am worried the leak is happening on clients now.

Last 14 Days memory usage. cloud run instance image

Last 1 Days memory usage. cloud run instance

image

You can observe from the above image that the memory usage is now constant at around 15% after I pushed the above code const posthog = (await import("posthog-js")).posthog;

How I was using PostHog before:

export const CSPostHogProvider = (props: IProps) => {
  const [client, setClient] = useState<PostHog | undefined>();

  useEffect(() => {
    const client = posthog.init(process.env["NEXT_PUBLIC_POSTHOG_KEY"] ?? "", {
      api_host: `${FRONT_END_URL}/ingest`,
      capture_pageview: false,
    });
    setClient(client);
  }, []);

  return <PostHogProvider client={client}>{props.children}</PostHogProvider>;
};

I tried this as well:

export const CSPostHogProvider = (props: IProps) => {
  const isClientSide = typeof window !== "undefined";
  if (isClientSide) {
    posthog.init(process.env["NEXT_PUBLIC_POSTHOG_KEY"] ?? "", {
      api_host: `${FRONT_END_URL}/ingest`,
      capture_pageview: false,
    });
  }

  return <PostHogProvider client={posthog}>{props.children}</PostHogProvider>;
};

I don't know if the leak is because of the way I configured PostHog or because of the library itself.

I am using [email protected]

Another concern is there are any plans about decreasing the size of the lib? https://github.com/PostHog/posthog-js/issues/65

mohamedgad21 avatar Sep 09 '24 17:09 mohamedgad21

image that's already states in their docs bro to do the dynamic import a.k.a lazy load the components.

volfadar avatar Sep 22 '24 03:09 volfadar

The photo or the screenshot is for loading the Page View component.

I clearly stated that the problem concerns the Provider component and initialization of the lib itself.

ghost avatar Sep 22 '24 03:09 ghost

And I don't think lazily loading the provider is good for performance.

ghost avatar Sep 22 '24 03:09 ghost

Hey, @mjad218!

I see you're using posthog slightly different from how we suggest you set it up. I believe you shouldn't be seeing any problems if you set up PostHog the following way

export const CSPostHogProvider = (props: IProps) => {
  useEffect(() => {
    posthog.init(process.env["NEXT_PUBLIC_POSTHOG_KEY"] ?? "", {
      api_host: `${FRONT_END_URL}/ingest`,
      capture_pageview: false,
    });
  }, []);

  return <PostHogProvider client={posthog}>{props.children}</PostHogProvider>;
};

This has a couple of benefits compared to what you've been doing:

  1. You're not sometimes rendering the provider and sometimes not, that'll trigger a complete rerender of your tree because you changed it heavily
  2. You're always passing a valid posthog instance to PostHogProvider rather than sometimes passing undefined - which we'll prevent soon

Do you mind trying that approach and letting me know if you're still seeing memory leaks? Thank you!

rafaeelaudibert avatar Jan 22 '25 22:01 rafaeelaudibert

Closing as a setup issue

timgl avatar May 26 '25 10:05 timgl